diff --git a/Makefile b/Makefile index ee2700ae7c..a26fc79599 100644 --- a/Makefile +++ b/Makefile @@ -228,6 +228,14 @@ ifndef USE_LOCAL_HEADERS USE_LOCAL_HEADERS=1 endif +ifndef WINFOUR +WINFOUR=0 +endif + +ifndef USE_REACTOS_WINSOCK_HEADER +USE_REACTOS_WINSOCK_HEADER=0 +endif + ifndef USE_RENDERER_DLOPEN USE_RENDERER_DLOPEN=1 endif @@ -244,6 +252,15 @@ ifndef SDL_VERSION SDL_VERSION=2 endif +ifeq ($(WINFOUR),1) + BASE_CFLAGS += -DWINFOUR + BASE_CFLAGS += -DUSE_REACTOS_WINSOCK_HEADER + BASE_CFLAGS += -DUSE_INTERNAL_JPEG + SDL_VERSION=1 + USE_CURL=0 + # CLIENTBIN=oa95 +endif + ############################################################################# BD=$(BUILD_DIR)/debug-$(PLATFORM)-$(ARCH) @@ -1141,6 +1158,10 @@ ifeq ($(USE_LOCAL_HEADERS),1) BASE_CFLAGS += -DUSE_LOCAL_HEADERS endif +ifeq ($(USE_REACTOS_WINSOCK_HEADER),1) + BASE_CFLAGS += -DUSE_REACTOS_WINSOCK_HEADER +endif + ifeq ($(BUILD_STANDALONE),1) BASE_CFLAGS += -DSTANDALONE endif @@ -1154,7 +1175,7 @@ endif ifeq ($(NO_STRIP),1) STRIP_FLAG = else - STRIP_FLAG = -s + STRIP_FLAG = -s endif BASE_CFLAGS += -DPRODUCT_VERSION=\\\"$(VERSION)\\\" @@ -1162,6 +1183,7 @@ BASE_CFLAGS += -Wformat=2 -Wno-format-zero-length -Wformat-security -Wno-format- BASE_CFLAGS += -Wstrict-aliasing=2 -Wmissing-format-attribute BASE_CFLAGS += -Wdisabled-optimization BASE_CFLAGS += -Werror-implicit-function-declaration +BASE_CFLAGS += -Wno-int-conversion ifeq ($(V),1) echo_cmd=@: @@ -1267,7 +1289,7 @@ endef ############################################################################# default: release -all: debug release +all: debug release debug: @$(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(BASE_CFLAGS) $(DEPEND_CFLAGS)" \ @@ -1757,6 +1779,7 @@ Q3ROAOBJ = \ $(B)/renderer_oa/tr_image_jpg.o \ $(B)/renderer_oa/tr_image_bmp.o \ $(B)/renderer_oa/tr_image_tga.o \ + $(B)/renderer_oa/tr_image_dds.o \ $(B)/renderer_oa/tr_image_pcx.o \ $(B)/renderer_oa/tr_init.o \ $(B)/renderer_oa/tr_light.o \ @@ -1831,6 +1854,7 @@ Q3RSOFTOBJ = \ $(B)/renderer_oa/tr_image_jpg.o \ $(B)/renderer_oa/tr_image_bmp.o \ $(B)/renderer_oa/tr_image_tga.o \ + $(B)/renderer_oa/tr_image_dds.o \ $(B)/renderer_oa/tr_image_pcx.o \ $(B)/renderer_oa/tr_init.o \ $(B)/renderer_oa/tr_light.o \ @@ -3020,8 +3044,8 @@ else @$(MAKE) VERSION=$(VERSION) -C $(LOKISETUPDIR) V=$(V) endif -dist: - git archive --format zip --output $(CLIENTBIN)-$(VERSION).zip HEAD +# dist: +# git archive --format zip --output $(CLIENTBIN)-$(VERSION).zip HEAD ############################################################################# # DEPENDENCIES diff --git a/Makefile.OpenArena b/Makefile.OpenArena index 7657f96c3a..7beee1636c 100644 --- a/Makefile.OpenArena +++ b/Makefile.OpenArena @@ -10,11 +10,13 @@ BUILD_CLIENT=1 BUILD_SERVER=1 BUILD_GAME_SO=0 BUILD_GAME_QVM=0 +USE_GIT=0 BUILD_BASEGAME=0 BUILD_MISSIONPACK=0 BASEGAME=baseoa # VERSION=1.36+0.8.8 -VERSION=3.0.0a +VERSION=TEST + # OpenArena doesn't use opus yet USE_CODEC_VORBIS=1 @@ -24,13 +26,17 @@ ifndef USE_CODEC_XMP USE_CODEC_XMP=1 endif +USE_CURL=1 + # FLTO Test OPTIMIZE += -flto -# This doesn't work with OpenArena yet +# Not supported BUILD_RENDERER_OPENGL2=0 # You can disable the renderer libraries and build in the OA renderer by default +# This is disabled because we have some client builtins used (trace etc) and +# we are scaling back some modularization for security and support reasons. USE_RENDERER_DLOPEN=0 # Choose version 1 or 2 @@ -58,6 +64,12 @@ CLIENTBIN=openarena SERVERBIN=oa_ded COPYDIR=/usr/local/games/openarena +# Use the Winsock2 headers from ReactOS, which doesn't give errors in Win9x +# USE_REACTOS_WINSOCK_HEADER=1 + +# Enable changes to allow Windows 95 and NT4 to work +# (Overrides enabling libraries above that don't work well, and outputs to oa95.exe) +WINFOUR=0 # DEBUG_CFLAGS=-ggdb -O0 diff --git a/code/cgame/cg_public.h b/code/cgame/cg_public.h index caefff0ac7..2592ab8015 100644 --- a/code/cgame/cg_public.h +++ b/code/cgame/cg_public.h @@ -183,7 +183,8 @@ typedef enum { CG_TESTPRINTINT, CG_TESTPRINTFLOAT, CG_ACOS, - CG_R_LFX_PARTICLEEFFECT // leilei - particle effects + CG_R_LFX_PARTICLEEFFECT, // leilei - particle effects + CG_R_VIEWPOSITION // leilei - view position } cgameImport_t; diff --git a/code/cgame/cg_syscalls.asm b/code/cgame/cg_syscalls.asm index f6f8d9efa7..fdbced3b72 100644 --- a/code/cgame/cg_syscalls.asm +++ b/code/cgame/cg_syscalls.asm @@ -104,3 +104,4 @@ equ testPrintInt -110 equ testPrintFloat -111 equ acos -112 equ trap_R_LFX_ParticleEffect -113 +equ trap_R_GetViewPosition -114 diff --git a/code/client/cl_cgame.c b/code/client/cl_cgame.c index 31a6a4d981..9d86e97176 100644 --- a/code/client/cl_cgame.c +++ b/code/client/cl_cgame.c @@ -637,7 +637,9 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { case CG_R_LFX_PARTICLEEFFECT: re.LFX_ParticleEffect( args[1], VMA(2), VMA(3)); return 0; - + case CG_R_VIEWPOSITION: + re.GetViewPosition( VMA(1) ); + return VMA(1); case CG_PC_ADD_GLOBAL_DEFINE: return botlib_export->PC_AddGlobalDefine( VMA(1) ); case CG_PC_LOAD_SOURCE: diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index ec8596a9a4..18fba60760 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -267,17 +267,17 @@ static sfx_t *S_FindName( const char *name ) { } if (!name[0]) { - Com_Printf( S_COLOR_YELLOW "WARNING: Sound name is empty\n" ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: Sound name is empty\n" ); return NULL; } if (strlen(name) >= MAX_QPATH) { - Com_Printf( S_COLOR_YELLOW "WARNING: Sound name is too long: %s\n", name ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: Sound name is too long: %s\n", name ); return NULL; } if (name[0] == '*') { - Com_Printf( S_COLOR_YELLOW "WARNING: Tried to load player sound directly: %s\n", name ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: Tried to load player sound directly: %s\n", name ); return NULL; } @@ -371,7 +371,7 @@ sfxHandle_t S_Base_RegisterSound( const char *name, qboolean compressed ) { if ( sfx->soundData ) { if ( sfx->defaultSound ) { - Com_Printf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName ); return 0; } return sfx - s_knownSfx; @@ -383,7 +383,7 @@ sfxHandle_t S_Base_RegisterSound( const char *name, qboolean compressed ) { S_memoryLoad(sfx); if ( sfx->defaultSound ) { - Com_Printf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName ); return 0; } @@ -1428,7 +1428,7 @@ static void S_OpenBackgroundStream( const char *filename ) { // Open stream s_backgroundStream = S_CodecOpenStream(filename); if(!s_backgroundStream) { - Com_Printf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", filename ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", filename ); return; } diff --git a/code/qcommon/net_ip.c b/code/qcommon/net_ip.c index 4ef3e3453c..71920137a4 100644 --- a/code/qcommon/net_ip.c +++ b/code/qcommon/net_ip.c @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # include # include # if WINVER < 0x501 + # ifdef __MINGW32__ // wspiapi.h isn't available on MinGW, so if it's // present it's because the end user has added it @@ -37,6 +38,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # endif # else # include +# endif + + // leilei - addition to fix win9x +# ifdef USE_REACTOS_WINSOCK_HEADER +# include "../reactos/wspiapi.h" # endif typedef int socklen_t; diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index f219f572d4..b631e13b6f 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -34,6 +34,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA //#define PRE_RELEASE_DEMO +// leilei - broken things + +//#define BROKEN_MDRPHYS // MDR physics are not serialized! +//#define BROKEN_IQM // crashes (and we don't plan to use the format anyway. IQM users are other games) + //============================================================================ // diff --git a/code/qcommon/qfiles.h b/code/qcommon/qfiles.h index 9f2b5fb23e..b3beb19b85 100644 --- a/code/qcommon/qfiles.h +++ b/code/qcommon/qfiles.h @@ -300,6 +300,22 @@ typedef struct { int ofsEnd; // end of file } mdrHeader_t; +#ifdef BROKEN_MDRPHYS +// leilei - bone deformery +// MDR loading also checks for a text file that can set these properties so the "MDP" code can get to work with them. +// and working from the cliententity. +typedef struct { + + vec3_t ofs[MDR_MAX_BONES]; + vec3_t wgt[MDR_MAX_BONES]; + float jiggle[MDR_MAX_BONES]; + +} mdrClBoneDeformSet_t; + +typedef struct { + mdrClBoneDeformSet_t def[4]; // up to 4 can alter bones +} mdrDeformity_t; +#endif /* ============================================================================== diff --git a/code/reactos/readme.md b/code/reactos/readme.md new file mode 100644 index 0000000000..dbc123d0ad --- /dev/null +++ b/code/reactos/readme.md @@ -0,0 +1,2 @@ +Place ReactOS' wspiapi.h file here. + diff --git a/code/renderer_oa/tr_animation.c b/code/renderer_oa/tr_animation.c index 7bcc5bdf69..182a98d836 100644 --- a/code/renderer_oa/tr_animation.c +++ b/code/renderer_oa/tr_animation.c @@ -177,6 +177,9 @@ R_MDRAddAnimSurfaces */ // much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c +#ifdef BROKEN_MDRPHYS +int TheRealMDL; // leilei HACK - tr.currentModel->index returns an incorrect index at this point, so we must set this from tr_main. +#endif void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { mdrHeader_t *header; @@ -217,6 +220,11 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { ent->e.oldframe = 0; } +#ifdef BROKEN_MDRPHYS + TheRealMDL = tr.currentModel->index; +#endif + + // // cull the entire model if merged bounding box of both frames // is outside the view frustum. @@ -302,6 +310,7 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd ); } } +extern float ProjectRadius( float r, vec3_t location ); /* ============== @@ -337,6 +346,21 @@ void RB_MDRSurfaceAnim( mdrSurface_t *surface ) frontlerp = 1.0f - backlerp; } + if (r_lerpbias->integer) + { + float projectedRadius, fsh, lerpscale, radius; + trRefEntity_t *ent = backEnd.currentEntity; + fsh = 1; + radius = 1; + lerpscale = r_lerpbias->value*-0.2; + if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) + { + fsh = 1.0f - projectedRadius * lerpscale; + } + if (fsh > 1) + backlerp = 0; + } + header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader); frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); @@ -519,3 +543,265 @@ void MC_UnCompress(float mat[3][4],const unsigned char * comp) val-=1<<(MC_BITS_VECT-1); mat[2][2]=((float)(val))*MC_SCALE_VECT; } + +#ifdef BROKEN_MDRPHYS + +/* +============== +RB_ClientDeformedMDRSurfaceAnim + +leilei - This is for supporting the eventual creation of player customization on special 'generic' player models + where sliders determine the body types. + + tl;dr: jiggle bones and body sliders. +============== +*/ + +vec3_t oldorg; +vec3_t neworg; +vec3_t oofs; +int thme; +int thmend; + +void RB_MDRP_Spring ( mdrBone_t bone, mdrPhysics_t phys, int bindex, vec3_t ofs, vec3_t ofs3, vec3_t ofs4, vec3_t bm1, vec3_t bm2, vec3_t bm3 ) +{ + vec3_t lfrom, lto, bold,bnew; + int i; + mdrPhysLocal_t *pl; + // Get our position + VectorCopy(ofs, lfrom); + + // Take in some of our animation's changes, exaggerate a bit + lto[0] = DotProduct( ofs, bm1 ) * 5; + lto[1] = DotProduct( ofs, bm2 ) * 5; + lto[2] = DotProduct( ofs, bm3 ) * 5; + + // Transform from the world + lfrom[0] = DotProduct( lto, backEnd.currentEntity->e.axis[0] ); + lfrom[1] = DotProduct( lto, backEnd.currentEntity->e.axis[1] ); + lfrom[2] = DotProduct( lto, backEnd.currentEntity->e.axis[2] ); + VectorAdd(lfrom,backEnd.currentEntity->e.origin, lfrom); + + pl = &backEnd.currentEntity->pl; + + if (tr.refdef.time > (pl->time[bindex] + 100)) + { + // it's either been too long since the last physics rendering, or the framerate is too low + // so reset the stuff + VectorCopy(lfrom, bold); + VectorCopy(lfrom, bnew); + VectorClear(pl->vel[bindex]); + pl->time[bindex] = tr.refdef.time + 16.667f; // 60fps + return; + } + + else if (tr.refdef.time > pl->time[bindex]) + { + int k; + VectorCopy(pl->neworg[bindex], bnew); + VectorCopy(pl->oldorg[bindex], bold); + for(k=0;k<3;k++) + { + float res = 0; + bnew[k] = (bnew[k] + bnew[k] + bold[k] + bnew[k]) / 4; + bold[k] = (bold[k] + lfrom[k] + lfrom[k] + bold[k]) / (4+res); + bold[k] += (pl->vel[bindex][k] * -phys.spring); // and a bit of spring + bold[k] += (pl->vel[bindex][k] * (-phys.spring * 0.5f)); // and a bit of spring + pl->vel[bindex][k]= (bnew[k] - bold[k]) * phys.limitl[k]; + } + VectorCopy(bnew, pl->neworg[bindex]); + VectorCopy(bold, pl->oldorg[bindex]); + pl->time[bindex] = tr.refdef.time + 16.667f; // 60fps + } + + ofs3[0] = DotProduct( pl->vel[bindex], backEnd.currentEntity->e.axis[0] ); + ofs3[1] = DotProduct( pl->vel[bindex], backEnd.currentEntity->e.axis[1] ); + ofs3[2] = DotProduct( pl->vel[bindex], backEnd.currentEntity->e.axis[2] ); + + for(i=0;i<3;i++) + { + ofs3[i] *= (phys.spring); + ofs4[i] = ofs3[i] * phys.limitr[i]; + ofs3[i] *= (phys.limitl[i]); + if (ofs3[i] > (phys.limitl[i]*4)) pl->vel[bindex][i] -= (pl->vel[bindex][i]*0.8); // there's a limit + } + + +} + +void RB_ClientDeformedMDRSurfaceAnim( mdrSurface_t *surface ) +{ + int i, j, k; + float frontlerp, backlerp; + int *triangles; + int indexes; + int baseIndex, baseVertex; + int numVerts; + int skipPhys = 0; + mdrVertex_t *v; + mdrHeader_t *header; + mdrFrame_t *frame; + mdrFrame_t *oldFrame; + mdrBone_t bones[MDR_MAX_BONES], *bonePtr, *bone; + model_t *mdl; + mdl = R_GetModelByHandle( backEnd.currentEntity->e.hModel ); + TheRealMDL = mdl->index; + + int frameSize; + + if (skipPhys || !r_mdrPhysics->integer) + { + RB_MDRSurfaceAnim( surface ); + return; + } + + //ri.Printf( PRINT_DEVELOPER, "DEFORMED! %i aka %s.......OR IS IT %i aka %s ?!??\n", tr.currentModel->index, tr.currentModel->name, TheRealMDL, tr.models[TheRealMDL]->name); + //ri.Printf(PRINT_WARNING,"MDP Rendered model index is %i\n", tr.currentModel->index); + // don't lerp if lerping off, or this is the only frame, or the last frame... + // + if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame) + { + backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used + frontlerp = 1; + } + else + { + backlerp = backEnd.currentEntity->e.backlerp; + frontlerp = 1.0f - backlerp; + } +// if (!r_lerpModels->integer) backlerp = 0; + + + header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader); + + frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); + + frame = (mdrFrame_t *)((byte *)header + header->ofsFrames + + backEnd.currentEntity->e.frame * frameSize ); + oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames + + backEnd.currentEntity->e.oldframe * frameSize ); + + RB_CheckOverflow( surface->numVerts, surface->numTriangles ); + + triangles = (int *) ((byte *)surface + surface->ofsTriangles); + indexes = surface->numTriangles * 3; + baseIndex = tess.numIndexes; + baseVertex = tess.numVertexes; + + // Set up all triangles. + for (j = 0 ; j < indexes ; j++) + { + tess.indexes[baseIndex + j] = baseVertex + triangles[j]; + } + tess.numIndexes += indexes; + + // + // lerp all the needed bones + // + if ( !backlerp ) + { + // no lerping needed + bonePtr = frame->bones; + } + + else + { + bonePtr = bones; + + for ( i = 0 ; i < header->numBones*12 ; i++ ) + { + ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i]; + } + + } + + // + // deform the vertexes by the lerped bones + // + numVerts = surface->numVerts; + v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts); + for ( j = 0; j < numVerts; j++ ) + { + + vec3_t tempVert, tempNormal; + mdrWeight_t *w; + + VectorClear( tempVert ); + VectorClear( tempNormal ); + w = v->weights; + + for ( k = 0 ; k < v->numWeights ; k++, w++ ) + { + vec3_t bmx[3]; + int p = 0; + // Set up the bones + bone = bonePtr + w->boneIndex; + + vec3_t ofs, ofs2, ofs3, ofs4; + + // Leilei - Iterate physics + + float tblend; + + tblend = 1.0; + VectorCopy(bone->matrix[0], bmx[0]); + VectorCopy(bone->matrix[1], bmx[1]); + VectorCopy(bone->matrix[2], bmx[2]); + + VectorCopy(w->offset, ofs); // Local offset to modify + VectorCopy(w->offset, ofs2); // Final offset to push to the rendering + if (tblend > 1) tblend = 1.0f; + if (tblend < 0) tblend = 0.0f; + + float wt21 = w->boneWeight; + float wt22 = w->boneWeight; + float wt23 = w->boneWeight; + + // Go through the known physics properties for the model + for(p=0;pphys.p[p].targbone == w->boneIndex) + { + if (mdl->phys.p[p].type == MDP_SPRING) + { + + RB_MDRP_Spring ( *bone, mdl->phys.p[p], w->boneIndex, ofs, ofs3, ofs4, bmx[0], bmx[1], bmx[2] ); + bmx[2][2] += (ofs4[2]); // rotate + + ofs2[0] += ofs3[0]; + ofs2[1] += ofs3[1]; + ofs2[2] += ofs3[2]; + + } + } + } + + + tempVert[0] += wt21 * ( DotProduct( bmx[0], ofs2 ) + bone->matrix[0][3] ); + tempVert[1] += wt22 * ( DotProduct( bmx[1], ofs2 ) + bone->matrix[1][3] ); + tempVert[2] += wt23 * ( DotProduct( bmx[2], ofs2 ) + bone->matrix[2][3] ); + + tempNormal[0] += wt21 * DotProduct( bmx[0], v->normal ); + tempNormal[1] += wt22 * DotProduct( bmx[1], v->normal ); + tempNormal[2] += wt23 * DotProduct( bmx[2], v->normal ); + + } + + tess.xyz[baseVertex + j][0] = tempVert[0]; + tess.xyz[baseVertex + j][1] = tempVert[1]; + tess.xyz[baseVertex + j][2] = tempVert[2]; + + tess.normal[baseVertex + j][0] = tempNormal[0]; + tess.normal[baseVertex + j][1] = tempNormal[1]; + tess.normal[baseVertex + j][2] = tempNormal[2]; + + tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; + tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; + + v = (mdrVertex_t *)&v->weights[v->numWeights]; + } + tess.numVertexes += surface->numVerts; +} + +#endif \ No newline at end of file diff --git a/code/renderer_oa/tr_backend.c b/code/renderer_oa/tr_backend.c index ff44597509..869e11ab41 100644 --- a/code/renderer_oa/tr_backend.c +++ b/code/renderer_oa/tr_backend.c @@ -849,6 +849,91 @@ void RB_BeginDrawingView (void) { #define MAC_EVENT_PUMP_MSEC 5 + +/* +=================== +R_RenderFlashblend + +leilei - GLQuake RenderDlights +Renders the classic GLQuake flashblend cone to subsitute dynamic lights. May be +a little redundant with r_flaresDlight +=================== +*/ +static void R_RenderFlashblend (dlight_t *light) +{ + int i; + float a; + vec3_t v; + float rad; + vec3_t vup, vpn, vright; + vec3_t point; + float ofs = 1; + + if ( (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) return; // leilei - don't draw flashblends in the UI + + VectorCopy( backEnd.refdef.viewaxis[0], vpn ); + VectorCopy( backEnd.refdef.viewaxis[1], vright ); + VectorCopy( backEnd.refdef.viewaxis[2], vup ); + + + rad = light->radius * 0.35f; + + for (int qj=0 ; qj<3 ; qj++) + v[qj] = light->origin[qj]; + + RB_BeginSurface( tr.coneShader, tess.fogNum ); + + for (i=0 ; i<3 ; i++) + tess.xyz[tess.numVertexes][i] = light->origin[i] - (vpn[i]*(rad*(ofs*.75))); + tess.vertexColors[tess.numVertexes][0] = light->color[0] * 64; + tess.vertexColors[tess.numVertexes][1] = light->color[1] * 64; + tess.vertexColors[tess.numVertexes][2] = light->color[2] * 64; + + // glquake's colors kick in if monolightmaps + if (r_monolightmaps->integer){ + tess.vertexColors[tess.numVertexes][0] = 0.3 * 255; + tess.vertexColors[tess.numVertexes][1] = 0.2 * 255; + tess.vertexColors[tess.numVertexes][2] = 0.0 * 255; + } + tess.vertexColors[tess.numVertexes][3] = 255; + tess.numVertexes++; + + for (int qi=0 ; qi<(17) ; qi++) + { + a = qi/(float)(16) * M_PI*2; + for (int qj=0 ; qj<3 ; qj++) + point[qj] = v[qj] + vright[qj]*cos(a)*rad + vup[qj]*sin(a)*rad; + VectorCopy (point, tess.xyz[tess.numVertexes] ); + tess.vertexColors[tess.numVertexes][0] = 0; + tess.vertexColors[tess.numVertexes][1] = 0; + tess.vertexColors[tess.numVertexes][2] = 0; + tess.vertexColors[tess.numVertexes][3] = 0; + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = qi; + tess.indexes[tess.numIndexes++] = qi+1; + tess.numVertexes++; + } + RB_EndSurface(); + +} + + +// leilei - go through the active dlights, and then draw them +static void RB_RenderFlashblends(void) { + int i; + if ( !backEnd.refdef.num_dlights ) { + return; + } + + for (i=0 ; iadditive == 2) + R_RenderFlashblend(dl); // this is definitely flashblend. + } + +}; + /* ================== RB_RenderDrawSurfList @@ -856,13 +941,13 @@ RB_RenderDrawSurfList */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; - int fogNum, oldFogNum; - int entityNum, oldEntityNum; - int dlighted, oldDlighted; + int fogNum, oldFogNum; + int entityNum, oldEntityNum; + int dlighted, oldDlighted; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; - int i; + int i; drawSurf_t *drawSurf; - int oldSort; + int oldSort; float originalTime; // save original time for entity shader offsets @@ -1038,6 +1123,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { // add the particles //R_AddParticles (); R_RenderParticles (); + RB_RenderFlashblends(); // add light flares on lights that aren't obscured RB_RenderFlares(); @@ -1371,6 +1457,7 @@ void RB_ShowImages( void ) { image_t *image; float x, y, w, h; int start, end; + float col = 1 * tr.identityLight; // leilei - overbright fix if ( !backEnd.projection2D ) { RB_SetGL2D(); @@ -1398,6 +1485,7 @@ void RB_ShowImages( void ) { GL_Bind( image ); qglBegin (GL_QUADS); + qglColor3f (col,col,col); // leilei - overbright fix qglTexCoord2f( 0, 0 ); qglVertex2f( x, y ); qglTexCoord2f( 1, 0 ); diff --git a/code/renderer_oa/tr_bsp.c b/code/renderer_oa/tr_bsp.c index d995c55625..19ac5c7a98 100644 --- a/code/renderer_oa/tr_bsp.c +++ b/code/renderer_oa/tr_bsp.c @@ -1878,6 +1878,9 @@ void RE_LoadWorldMap( const char *name ) { tr.sunDirection[0] = 0.45f; tr.sunDirection[1] = 0.3f; tr.sunDirection[2] = 0.9f; + + // leilei - deactivate sun and flare if it ain't there + tr.sunOn = 0; tr.sunFlare = 0; tr.sunShaderCustom = 0; VectorNormalize( tr.sunDirection ); @@ -1929,6 +1932,12 @@ void RE_LoadWorldMap( const char *name ) { R_LoadEntities( &header->lumps[LUMP_ENTITIES] ); R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] ); + // leilei - load our specific custom sun here + if (tr.sunShaderCustom) + tr.sunShader = R_FindShader( tr.sunShaderCustom, LIGHTMAP_NONE, qtrue ); + else + tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue ); + s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker; // only set tr.world now that we know the entire level has loaded properly diff --git a/code/renderer_oa/tr_extensions.c b/code/renderer_oa/tr_extensions.c index 150d660909..fc0f7dfd23 100644 --- a/code/renderer_oa/tr_extensions.c +++ b/code/renderer_oa/tr_extensions.c @@ -112,6 +112,12 @@ GLvoid (APIENTRYP qglGetVertexAttribPointervARB) (GLuint index, GLenum pname, GL GLvoid (APIENTRYP qglColorTableEXT)( GLint, GLint, GLint, GLint, GLint, const GLvoid *); GLvoid (APIENTRYP qglColorTableSGI)( GLint, GLint, GLint, GLint, GLint, const GLvoid *); +// leilei - DDS/DXT + +GLvoid (APIENTRYP qglCompressedTexImage2DARB) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); +GLvoid (APIENTRYP qglColorTableEXT)( GLint, GLint, GLint, GLint, GLint, const GLvoid *); +GLvoid (APIENTRYP qglColorTableSGI)( GLint, GLint, GLint, GLint, GLint, const GLvoid *); + /* typedef enum { GLHW_GENERIC, // where everthing works the way it should @@ -272,6 +278,26 @@ void GLimp_InitExtraExtensions() { ri.Printf( PRINT_ALL, "...GL_EXT_paletted_texture not found\n" ); } + // leilei - DDS/DXT + textureCompressionSupport = qfalse; + if ( GLimp_HaveExtension( "GL_ARB_texture_compression" ) ) + { + if ( r_loadDDS->integer ) { + qglCompressedTexImage2DARB = (GLvoid (APIENTRYP)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) SDL_GL_GetProcAddress("glCompressedTexImage2DARB"); + { + ri.Printf( PRINT_ALL, "...using GL_ARB_texture_compression\n"); + textureCompressionSupport = qtrue; + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_ARB_texture_compression\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_ARB_texture_compression not found\n" ); + } #ifdef _WIN32 // leilei - 3dfx gamma diff --git a/code/renderer_oa/tr_flares.c b/code/renderer_oa/tr_flares.c index b8a6b06590..495d6a5991 100644 --- a/code/renderer_oa/tr_flares.c +++ b/code/renderer_oa/tr_flares.c @@ -1330,11 +1330,31 @@ void RB_DrawSunFlare( void ) return; } + // leilei - don't draw the flare if we ain't got the sun + if ( !r_drawSun->integer ) { + return; + } + + // don't draw the flare if we don't define the sun + if ( r_drawSun->integer == 1 && (!tr.sunOn) ) { + return; + } + if ( backEnd.doneSunFlare) // leilei - only do sun once return; + if (backEnd.viewParms.isPortal) // leilei - do sun only not in the portal (keeps sun from disappearing when portal is onscreen) + return; + fetype = r_flareSun->integer; + // if we specified a flare type for sunshader in the sky, then we use it. + if (tr.sunOn && (r_drawSun->integer == 1)) { + fetype = tr.sunFlare; + } + // but, if we don't want the sunflare (type is 0 - either on the r_drawSun 2 override or the shader) then we just forget it + if (fetype == 0) return; + qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); diff --git a/code/renderer_oa/tr_image.c b/code/renderer_oa/tr_image.c index 898e0a8ce0..13941f1c3d 100644 --- a/code/renderer_oa/tr_image.c +++ b/code/renderer_oa/tr_image.c @@ -531,8 +531,8 @@ void R_ImageList_f( void ) { sizeSuffix = "Gb"; } - //ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName); - ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s %f %f\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName, image->loadTime, image->procTime); + ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName); + //ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s %f %f\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName, image->loadTime, image->procTime); estTotalSize += estSize; estTotalTimeLoaded += image->loadTime + image->procTime; @@ -2131,6 +2131,10 @@ Finds or loads the given image. Returns NULL if it fails, not a default image. ============== */ +#ifdef BROKEN_DDS +// DDS/DXT +image_t *R_LoadDDSImage(const char *name, int bits, filterType_t filterType, wrapType_t wrapType); +#endif image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) { image_t *image; @@ -2140,7 +2144,9 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) long hash; float oldtime; float loadtime; - +#ifdef BROKEN_DDS + char ddsName[1024]; +#endif if (!name) { return NULL; } @@ -2162,6 +2168,31 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) return image; } } +#ifdef BROKEN_DDS + // leilei - DDS - do it here, so we can have a hardware compressed texture instead. The normal means of texture loading expects pixels to be returned which we won't do. + if(textureCompressionSupport && r_loadDDS->integer) + { + int bits; // no bits + int whatclamp; + Q_strncpyz(ddsName, name, sizeof(ddsName)); + COM_StripExtension(ddsName, ddsName, sizeof(ddsName)); + Q_strcat(ddsName, sizeof(ddsName), ".dds"); + + // if (glWrapClampMode == GL_CLAMP_TO_EDGE) + // whatclamp = WT_CLAMP; + // else + // whatclamp = WT_REPEAT; + // try to load a customized .dds texture + + image = R_LoadDDSImage(ddsName, bits, 0, whatclamp); + if(image != NULL) + { + // ri.Printf(PRINT_ALL, "found custom .dds '%s'\n", ddsName); + return image; + } + } + +#endif // leilei - Detail texture hack // to kill artifacts of shimmer of pattern of terrible @@ -2323,6 +2354,56 @@ image_t *R_FindImageFileIfItsThere( const char *name, imgType_t type, imgFlags_t } + + +/* +================ +Rebecca Heineman + + 1963-2025 + +Jennell Jaquays + + 1956-2024 +================ +*/ + +static void R_ebeccaHeineman( void ) { + int x,y; + byte data[16][16][4]; + + for (x=0 ; x<16 ; x++) { + for (y=0 ; y<16 ; y++) { + + if (y<3 || y>12) // blue + { + data[y][x][0] = 31; + data[y][x][1] = 206; + data[y][x][2] = 250; + } + else if (y<6 || y>9) // pink + { + data[y][x][0] = 245; + data[y][x][1] = 169; + data[y][x][2] = 184; + } + else // white + { + data[y][x][0] = 255; + data[y][x][1] = 255; + data[y][x][2] = 255; + } + // data[y][x][0] = + // data[y][x][1] = + // data[y][x][2] = b; + data[y][x][3] = 255; + } + } + tr.transRights = R_CreateImage("thankYouRebeccaHeineman&JennellJaquays", (byte *)data, 16, 16, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 ); +} + + + /* ================ R_CreateDlightImage @@ -2530,6 +2611,7 @@ void R_CreateBuiltinImages( void ) { tr.scratchImage[x] = R_CreateImage("*scratch", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_PICMIP | IMGFLAG_CLAMPTOEDGE, 0); } + R_ebeccaHeineman(); R_CreateDlightImage(); @@ -2953,3 +3035,44 @@ void R_SkinList_f( void ) { ri.Printf (PRINT_ALL, "------------------\n"); } +#ifdef BROKEN_DDS +// leilei - for DDS loading, which relies on this function... +/* +================ +R_AllocImage +================ +*/ +image_t *R_AllocImage(const char *name, qboolean linkIntoHashTable) +{ + image_t *image; + long hash; + char buffer[1024]; + +// if(strlen(name) >= MAX_QPATH) + if(strlen(name) >= 1024) + { + ri.Error(ERR_DROP, "R_AllocImage: \"%s\" image name is too long\n", name); + return NULL; + } + + image = ri.Hunk_Alloc(sizeof(image_t), h_low); + Com_Memset(image, 0, sizeof(image_t)); + + + qglGenTextures(1, &image->texnum); + + //Com_AddToGrowList(&tr.images, image); + + Q_strncpyz(image->imgName, name, sizeof(image->imgName)); + + if(linkIntoHashTable) + { + Q_strncpyz(buffer, name, sizeof(buffer)); + hash = generateHashValue(buffer); + image->next = hashTable[hash]; + hashTable[hash] = image; + } + + return image; +} +#endif \ No newline at end of file diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index a148083089..cfd7032617 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -29,6 +29,7 @@ int maxAnisotropy = 0; float displayAspect = 0.0f; qboolean vertexShaders = qfalse; qboolean postprocess = qfalse; +qboolean textureCompressionSupport = qfalse; // leilei - compressed textures qboolean palettedTextureSupport = qfalse; // leilei - paletted textures char depthimage; @@ -105,6 +106,7 @@ cvar_t *r_ext_texture_env_add; cvar_t *r_ext_texture_filter_anisotropic; cvar_t *r_ext_max_anisotropy; cvar_t *r_ext_vertex_shader; +cvar_t *r_loadDDS; // leilei - loading DDS textures cvar_t *r_ext_paletted_texture; // leilei - Paletted Texture cvar_t *r_ext_gamma_control; // leilei - 3dfx gamma control cvar_t *r_postprocess; @@ -212,6 +214,9 @@ cvar_t *r_mockvr; // Leilei - for debugging PVR only! cvar_t *r_leifx; // Leilei - leifx nostalgia filter cvar_t *r_shadeMethod; // Leilei cvar_t *r_particles; // Leilei - particle effects motif +#ifdef BROKEN_MDRPHYS +cvar_t *r_mdrPhysics; // Leilei - mdr physics +#endif cvar_t *r_skytess; // leilei - lower detail of skies @@ -222,6 +227,8 @@ cvar_t *r_suggestiveThemes; // leilei - mature content control cvar_t *r_textureDither; // leilei - Dithered texture +cvar_t *r_lerpbias; // Leilei - lerping bias + // leilei - fallback shader hack @@ -1129,6 +1136,7 @@ void R_Register( void ) r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "2", CVAR_ARCHIVE | CVAR_LATCH ); + r_loadDDS = ri.Cvar_Get( "r_loadDDS", "1", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - compressed texture support r_ext_paletted_texture = ri.Cvar_Get( "r_ext_paletted_texture", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - paletted texture support r_ext_gamma_control = ri.Cvar_Get( "r_ext_gamma_control", "1", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - 3dfx gamma support @@ -1196,7 +1204,7 @@ void R_Register( void ) r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE ); r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE ); r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE ); - r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE ); + r_drawSun = ri.Cvar_Get( "r_drawSun", "1", CVAR_ARCHIVE ); // leilei - default 1 for allowing sky shaders to define a sun. r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE ); r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE ); r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE); @@ -1305,8 +1313,13 @@ void R_Register( void ) r_leidebug = ri.Cvar_Get( "r_leidebug", "0" , CVAR_CHEAT); r_particles = ri.Cvar_Get( "r_particles", "0" , CVAR_ARCHIVE | CVAR_LATCH); +#ifdef BROKEN_MDRPHYS + r_mdrPhysics = ri.Cvar_Get( "r_mdrPhysics", "0" , CVAR_ARCHIVE); +#endif r_leidebugeye = ri.Cvar_Get( "r_leidebugeye", "0" , CVAR_CHEAT); + r_lerpbias = ri.Cvar_Get( "r_lerpbias", "-2" , CVAR_ARCHIVE); + r_iconmip = ri.Cvar_Get ("r_iconmip", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - icon mip r_iconBits = ri.Cvar_Get ("r_iconBits", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - icon bits @@ -1725,6 +1738,7 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) re.AddRefEntityToScene = RE_AddRefEntityToScene; re.AddPolyToScene = RE_AddPolyToScene; re.LFX_ParticleEffect = LFX_ParticleEffect; + re.GetViewPosition = RE_GetViewPosition; re.LightForPoint = R_LightForPoint; re.AddLightToScene = RE_AddLightToScene; re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene; diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index d524c1e68f..0ae6b4aae6 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -1,3 +1,4 @@ + /* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. @@ -30,7 +31,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../renderercommon/tr_public.h" #include "../renderercommon/tr_common.h" +#ifdef BROKEN_IQM #include "../renderercommon/iqm.h" +#endif #include "../renderercommon/qgl.h" #define GL_INDEX_TYPE GL_UNSIGNED_INT @@ -47,6 +50,7 @@ typedef unsigned int glIndex_t; #define SHADERNUM_BITS 14 #define MAX_SHADERS (1<type = MOD_BAD; return 0; } - +#ifdef BROKEN_MDRPHYS + isMDP = 0; +#endif ident = LittleLong(*(unsigned *)buf.u); if(ident == MDR_IDENT) loaded = R_LoadMDR(mod, buf.u, filesize, name); @@ -146,6 +150,142 @@ qhandle_t R_RegisterMDR(const char *name, model_t *mod) return mod->index; } +#ifdef BROKEN_MDRPHYS + +/* +==================== +R_RegisterMDP + +leilei - MDR with additional defined properties for secondary physics +==================== +*/ +qhandle_t R_RegisterMDP(const char *name, model_t *mod) +{ + union { + unsigned *u; + void *v; + } buf; + int ident; + qboolean loaded = qfalse; + int filesize; + isMDP = 1; + filesize = ri.FS_ReadFile(name, (void **) &buf.v); + if(!buf.u) + { + mod->type = MOD_BAD; + return 0; + } + // leilei - find a config.... + { + int stop = 0; + char cfgName[ MAX_QPATH ]; + char *text_p; + int len; + int i; + char *token; + char text[16384]; + fileHandle_t f; + + // Find our Physics definition file + COM_StripExtension( name, cfgName, MAX_QPATH ); + sprintf(cfgName,"%s.phy",cfgName); + + len = FS_FOpenFileRead(cfgName, &f, qtrue); + if (len <= 0) { + ri.Printf(PRINT_WARNING,"R_RegisterMDP: Couldn't find the %s file, will continue without physics\n", cfgName); + stop=1; + } + if (len >= sizeof ( text) - 1) { + //ri.Printf(PRINT_WARNING,"R_RegisterMDP: Physics file %s is too long\n", cfgName); + FS_FCloseFile (f); + stop=1; + } + if (!stop){ + FS_Read(text, len, f); + text[len] = 0; + FS_FCloseFile(f); + + // parse the text + text_p = text; + + ri.Printf(PRINT_WARNING,"MDP - this is model index %i", mod->index); + ri.Printf(PRINT_WARNING,"R_RegisterMDP: Physics reading.....\n"); + int thep = 0; + + isMDP = 1; // yep, there's physics here + + while (1) { + + token = COM_Parse(&text_p); + if ( !token[0] ) { + break; + } + //token = COM_Parse(&text_p); + if (!Q_stricmp(token, "suggestive")){ // allow user to turn off the physics after this mark + if (r_suggestiveThemes->integer < 1) break; + + else + { + token = COM_Parse(&text_p); + } + } + if (!Q_stricmp(token, "spring")) { + token = COM_Parse(&text_p); + ri.Printf(PRINT_WARNING,"R_RegisterMDP: Physic %i: spring\n",thep); + mod->phys.p[thep].type= MDP_SPRING; + + + //token = COM_Parse(&text_p); + ri.Printf(PRINT_WARNING,"Spring parameters: %i bonenumber", atoi(token)); + mod->phys.p[thep].targbone=atoi(token); + // default parms + mod->phys.p[thep].spring = 0.30f; + mod->phys.p[thep].limitl[0] = 0.3f; + mod->phys.p[thep].limitl[1] = 0.3f; + mod->phys.p[thep].limitl[2] = 0.9f; + mod->phys.p[thep].limitr[0] = 0.15f; + mod->phys.p[thep].limitr[1] = 0.15f; + mod->phys.p[thep].limitr[2] = 0.15f; + + token = COM_Parse(&text_p); + ri.Printf(PRINT_WARNING,"%f springiness\n", atof(token)); + mod->phys.p[thep].spring=atof(token); + mod->phys.p[thep].limitl[0] *= mod->phys.p[thep].spring; + mod->phys.p[thep].limitl[1] *= mod->phys.p[thep].spring; + mod->phys.p[thep].limitl[2] *= mod->phys.p[thep].spring; + + thep++; + continue; + + } + break; + } + } + + + } + + + ident = LittleLong(*(unsigned *)buf.u); + if(ident == MDR_IDENT) + { + // Check if there's a physics config + loaded = R_LoadMDR(mod, buf.u, filesize, name); + } + + ri.FS_FreeFile (buf.v); + + if(!loaded) + { + ri.Printf(PRINT_WARNING,"R_RegisterMDP: couldn't load mdr file %s\n", name); + mod->type = MOD_BAD; + return 0; + } + return mod->index; +} + +#endif +#ifdef BROKEN_IQM /* ==================== R_RegisterIQM @@ -181,7 +321,7 @@ qhandle_t R_RegisterIQM(const char *name, model_t *mod) return mod->index; } - +#endif typedef struct { @@ -193,8 +333,14 @@ typedef struct // when there are multiple models of different formats available static modelExtToLoaderMap_t modelLoaders[ ] = { +#ifdef BROKEN_IQM { "iqm", R_RegisterIQM }, +#endif +#ifdef BROKEN_MDRPHYS + { "mdr", R_RegisterMDP }, +#else { "mdr", R_RegisterMDR }, +#endif { "md3", R_RegisterMD3 } }; static int numModelLoaders = ARRAY_LEN(modelLoaders); @@ -763,6 +909,10 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char // first do some copying stuff surf->ident = SF_MDR; +#ifdef BROKEN_MDRPHYS + if (isMDP) + surf->ident = SF_MDP; +#endif Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name)); Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader)); @@ -1078,11 +1228,14 @@ int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFram R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, start); R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, end); } +#ifdef BROKEN_IQM else if( model->type == MOD_IQM ) { return R_IQMLerpTag( tag, model->modelData, startFrame, endFrame, frac, tagName ); - } else { + } +#endif + else { AxisClear( tag->axis ); VectorClear( tag->origin ); @@ -1154,7 +1307,9 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { VectorCopy( frame->bounds[1], maxs ); return; - } else if(model->type == MOD_IQM) { + } +#ifdef BROKEN_IQM + else if(model->type == MOD_IQM) { iqmData_t *iqmData; iqmData = model->modelData; @@ -1166,7 +1321,7 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { return; } } - +#endif VectorClear( mins ); VectorClear( maxs ); } diff --git a/code/renderer_oa/tr_model_iqm.c b/code/renderer_oa/tr_model_iqm.c index be7cf992c4..8c59a5a31b 100644 --- a/code/renderer_oa/tr_model_iqm.c +++ b/code/renderer_oa/tr_model_iqm.c @@ -20,7 +20,7 @@ along with Quake III Arena source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ - +#ifdef BROKEN_IQM #include "tr_local.h" #define LL(x) x=LittleLong(x) @@ -1184,3 +1184,5 @@ int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, return qtrue; } + +#endif \ No newline at end of file diff --git a/code/renderer_oa/tr_scene.c b/code/renderer_oa/tr_scene.c index fa1773e13c..0db0c65b5f 100644 --- a/code/renderer_oa/tr_scene.c +++ b/code/renderer_oa/tr_scene.c @@ -241,10 +241,6 @@ void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, floa if ( intensity <= 0 ) { return; } - // these cards don't have the correct blend mode - if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - return; - } dl = &backEndData->dlights[r_numdlights++]; @@ -266,6 +262,26 @@ void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, floa dl->color[1] = g; dl->color[2] = b; dl->additive = additive; + + // leilei - q3r/alice mode + if ( r_dynamiclight->integer == 2){ + + dl->color[0] = r * 0.1; + dl->color[1] = g * 0.1; + dl->color[2] = b * 0.1; + dl->additive = 1; + } + + // these cards don't have the correct blend mode + // leilei - so force additive and keep going + if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { + dl->additive = 1; + } + + // leilei - glquake mode - 2 shuts off the light projection to make room for flashblend + if ( r_dynamiclight->integer == 3) + dl->additive = 2; + } /* @@ -374,9 +390,10 @@ void RE_RenderScene( const refdef_t *fd ) { // turn off dynamic lighting globally by clearing all the // dlights if it needs to be disabled or if vertex lighting is enabled - if ( r_dynamiclight->integer == 0 || + if ( r_dynamiclight->integer == 0 // || // r_vertexLight->integer == 1 || // leilei - commented this out, as we can now do dynamic lights with vertex light - glConfig.hardwareType == GLHW_PERMEDIA2 ) { + // glConfig.hardwareType == GLHW_PERMEDIA2 // leilei - commented this out, as permedia should play with flashblend/verts + ) { tr.refdef.num_dlights = 0; } diff --git a/code/renderer_oa/tr_shade.c b/code/renderer_oa/tr_shade.c index 88d6f0bd75..bbc9604fd3 100644 --- a/code/renderer_oa/tr_shade.c +++ b/code/renderer_oa/tr_shade.c @@ -644,6 +644,12 @@ static void ProjectDlightTexture_scalar( void ) { colors = colorArray[0]; dl = &backEnd.refdef.dlights[l]; + + if ( dl->additive == 2) // leilei - glquake flashblend mode + { + return; + } + VectorCopy( dl->transformed, origin ); radius = dl->radius; scale = 1.0f / radius; @@ -803,6 +809,52 @@ static void RB_FogPass( void ) { R_DrawElements( tess.numIndexes, tess.indexes ); } + +/* +=================== +RE_GetViewPosition + +leilei + +Returns a vector of the point that is from the renderer. Used to (try) getting accurate positions +of things in the world for Cgame to work with, where cgame may (likely) fail. +=================== +*/ + +void RE_GetViewPosition(vec3_t point) +{ + vec4_t eye, clip, normalized, window; + int i; + R_TransformModelToClip( point, backEnd.or.modelMatrix, + backEnd.viewParms.projectionMatrix, eye, clip ); + + // check to see if the point is completely off screen + for ( i = 0 ; i < 3 ; i++ ) { + if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) { + point[0] = -666; + point[1] = -666; + return; + } + } + + R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window ); + + if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth + || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) { + point[0] = -666; + point[1] = -666; + return; // shouldn't happen, since we check the clip[] above, except for FP rounding + } + + point[0] = (float)(backEnd.viewParms.viewportX + window[0]); + point[1] = (float)(backEnd.viewParms.viewportY + window[1]); + + point[2] = 0; + //return there; +} + + + /* =============== ComputeColors @@ -1025,7 +1077,7 @@ static void ComputeColors( shaderStage_t *pStage ) // TODO break; case CMOD_BAD: - return; + break; } // diff --git a/code/renderer_oa/tr_shade_calc.c b/code/renderer_oa/tr_shade_calc.c index 7d3018fc78..bc56b854da 100644 --- a/code/renderer_oa/tr_shade_calc.c +++ b/code/renderer_oa/tr_shade_calc.c @@ -1588,7 +1588,7 @@ static void RB_UVColor( unsigned char *colors, int glowcol, int fx ) v = tess.xyz[0]; normal = tess.normal[0]; - texc = tess.texCoords[0]; + texc = (float*) tess.texCoords[0]; numVertexes = tess.numVertexes; for (i = 0 ; i < numVertexes ; i++, v += 4, texc+=2 ) { @@ -1818,6 +1818,7 @@ void RB_CalcDiffuseColor( unsigned char *colors ) { RB_CalcMaterials( colors, 0xFFFFFF, 0x808080, 0x808080, 0x000000, 128, 255 ); } +#ifdef BROKEN_SHADELOD // leilei: FIXME this does not work as intended else if ((r_shadeMethod->integer > 150) && (r_shadeMethod->integer < 667)) // values in a certain range is an adaptive LOD selection of -1, 0 and 3 { float projectedRadius, fsh, shadescale, radius; @@ -1838,11 +1839,19 @@ void RB_CalcDiffuseColor( unsigned char *colors ) RB_CalcDiffuseColor_flat( colors ); } +#endif // BROKEN else // standard idtech3 shading { RB_CalcDiffuseColor_scalar( colors ); } + // leilei - glow property + if ((backEnd.currentEntity->e.glow >= 1337 && backEnd.currentEntity->e.glow <= 1340 )) // look for 1337-1340 as compatibility so we don't get malformed glows from old cgames + { + RB_GlowBlend( colors, backEnd.currentEntity->e.glowcol, (backEnd.currentEntity->e.glow - 1337) ); + } + + } @@ -2201,6 +2210,11 @@ void RB_CalcMaterials( unsigned char *colors, int ambient, int diffuse, int spec // TODO: Low detail materials RB_CalcMaterialColor( colors, 1, ambient, diffuse, specular, emissive, spechard, alpha ); + // leilei - glow property + if ((backEnd.currentEntity->e.glow >= 1337 && backEnd.currentEntity->e.glow <= 1340 )) // look for 1337-1340 as compatibility so we don't get malformed glows from old cgames + { + RB_GlowBlend( colors, backEnd.currentEntity->e.glowcol, (backEnd.currentEntity->e.glow - 1337) ); + } } diff --git a/code/renderer_oa/tr_shader.c b/code/renderer_oa/tr_shader.c index a279e1ebbd..2d4f0d1aee 100644 --- a/code/renderer_oa/tr_shader.c +++ b/code/renderer_oa/tr_shader.c @@ -2988,7 +2988,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbMod in shader '%s'\n", shader.name ); continue; } - if ( !Q_stricmp( token, "glow" ) ) + else if ( !Q_stricmp( token, "glow" ) ) { // TODO: Parse "entity" and "vertex" for their colors, for railguns and maps token = COM_ParseExt( text, qfalse ); @@ -3008,7 +3008,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) stage->rgbMod = CMOD_GLOW; } - if ( !Q_stricmp( token, "uvcol" ) ) + else if ( !Q_stricmp( token, "uvcol" ) ) { // Parse color token = COM_ParseExt( text, qfalse ); @@ -3028,22 +3028,22 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) stage->rgbMod = CMOD_UVCOL; } - if ( !Q_stricmp( token, "normtoalpha" ) ) + else if ( !Q_stricmp( token, "normtoalpha" ) ) { // normalize colors, but average color prior is alpha. stage->rgbMod = CMOD_NORMALIZETOALPHA; } - if ( !Q_stricmp( token, "normtoalphafast" ) ) + else if ( !Q_stricmp( token, "normtoalphafast" ) ) { // normalize and use the first vert's color on whole surface, but average color prior is alpha. stage->rgbMod = CMOD_NORMALIZETOALPHAFAST; } - if ( !Q_stricmp( token, "lighting" ) ) + else if ( !Q_stricmp( token, "lighting" ) ) { // modulate a standard diffuse light on top of existing vertex colors stage->rgbMod = CMOD_LIGHTING; } - if ( !Q_stricmp( token, "opaque" ) ) + else if ( !Q_stricmp( token, "opaque" ) ) { // modulate a standard diffuse light on top of existing vertex colors stage->rgbMod = CMOD_OPAQUE; @@ -3604,6 +3604,38 @@ static qboolean ParseShader( char **text ) SkipRestOfLine( text ); continue; } + + // leilei - Parse a shader for the sun, and a type of flare for the number after it. + // Inspired by ET's sunShader (my own implementation) + else if ( !Q_stricmp( token, "sunShader" ) ) { + // load a sun shader to override our default shader + token = COM_ParseExt( text, qfalse ); + + tr.sunShaderCustom = CopyString(token); // leilei - copy the shader's name so we can load it properly elsewhere (doing it here would make a broken sun) + tr.sunOn = 1; // activate sun to be rendered for r_drawSun 1. + + // the next one is the flare type. + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + tr.sunFlare = 0; // dont flare if we dont specify + continue; + } + tr.sunFlare = atoi( token ); + + // the next one is a size multiplier. + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + tr.sunOn = 1; // sun is always normal size if we don't specify + continue; + } + if (atof( token )>1) + tr.sunOn = atof( token ); + + continue; + } + // sun parms else if ( !Q_stricmp( token, "q3map_sun" ) ) { float a, b; @@ -5346,9 +5378,11 @@ a single large text block that can be scanned for shader names ===================== */ #define MAX_SHADER_FILES 4096 + static void ScanAndLoadShaderFiles( void ) { char **shaderFiles; + char *buffers[MAX_SHADER_FILES]; char *p; int numShaderFiles; @@ -5368,10 +5402,6 @@ static void ScanAndLoadShaderFiles( void ) return; } - if ( numShaderFiles > MAX_SHADER_FILES ) { - numShaderFiles = MAX_SHADER_FILES; - } - // load and parse shader files for ( i = 0; i < numShaderFiles; i++ ) { @@ -5383,7 +5413,7 @@ static void ScanAndLoadShaderFiles( void ) if ( !buffers[i] ) ri.Error( ERR_DROP, "Couldn't load %s", filename ); - + // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders. p = buffers[i]; COM_BeginParseSession(filename); @@ -5426,9 +5456,12 @@ static void ScanAndLoadShaderFiles( void ) if (buffers[i]) sum += summand; } + if ( numShaderFiles > MAX_SHADER_FILES ) { + numShaderFiles = MAX_SHADER_FILES; + } // build single large buffer - s_shaderText = ri.Hunk_Alloc( sum + numShaderFiles*2, h_low ); + s_shaderText = ri.Hunk_Alloc( sum + (numShaderFiles*2), h_low ); s_shaderText[ 0 ] = '\0'; textEnd = s_shaderText; @@ -5521,6 +5554,15 @@ static void CreateInternalShaders( void ) { Q_strncpyz( shader.name, "", sizeof( shader.name ) ); shader.sort = SS_STENCIL_SHADOW; tr.shadowShader = FinishShader(); + + // leilei - cone shader for flashblend + Q_strncpyz( shader.name, "", sizeof( shader.name ) ); + stages[0].bundle[0].image[0] = tr.whiteImage; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_VERTEX; + stages[0].alphaGen = AGEN_VERTEX; + stages[0].stateBits = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE; + tr.coneShader = FinishShader(); } static void CreateExternalShaders( void ) { @@ -5567,9 +5609,6 @@ static void CreateExternalShaders( void ) { } } - - tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue ); - // leilei - placeholder shaders tr.placeholderTextureShader = R_FindShader( "placeholder_texture", LIGHTMAP_NONE, qtrue ); tr.placeholderModelShader = R_FindShader( "placeholder_model", LIGHTMAP_NONE, qtrue ); diff --git a/code/renderer_oa/tr_sky.c b/code/renderer_oa/tr_sky.c index f09d69c641..edc3072d42 100644 --- a/code/renderer_oa/tr_sky.c +++ b/code/renderer_oa/tr_sky.c @@ -716,7 +716,6 @@ void RB_DrawSun( void ) { float size; float dist; vec3_t origin, vec1, vec2; - vec3_t temp; if ( !backEnd.skyRenderedThisView ) { return; @@ -726,15 +725,33 @@ void RB_DrawSun( void ) { return; } + // leilei - do the actual sun check, for our default behavior + if ( r_drawSun->integer == 1 && !tr.sunOn ) { + return; + } + + if ( (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) return; // leilei - don't bother with sun if we don't world. Possible crash prevention to an uninitialized sun + + if ( !tr.sunShader ) // leilei - if we somehow, did not load a sun shader at all for some reason, don't try + return; + if ( backEnd.doneSun) // leilei - only do sun once return; + if (backEnd.viewParms.isPortal) // leilei - do sun only not in the portal (keeps sun from disappearing when portal is onscreen) + return; + qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) size = dist * 0.4; + // leilei - allow the size of the sun to be changed + if (tr.sunOn) + size *= tr.sunOn; + + size *= -1; // inverse to fix flip // leilei - SUN color vec3_t coll; @@ -766,62 +783,16 @@ void RB_DrawSun( void ) { // farthest depth range qglDepthRange( 1.0, 1.0 ); - - - - // FIXME: use quad stamp RB_BeginSurface( tr.sunShader, tess.fogNum ); - VectorCopy( origin, temp ); - VectorSubtract( temp, vec1, temp ); - VectorSubtract( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; - - VectorCopy( origin, temp ); - VectorAdd( temp, vec1, temp ); - VectorSubtract( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; - - VectorCopy( origin, temp ); - VectorAdd( temp, vec1, temp ); - VectorAdd( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; - - VectorCopy( origin, temp ); - VectorSubtract( temp, vec1, temp ); - VectorAdd( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 1; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 3; + // leilei - for quadstamp + byte colb[4]; + colb[0] = coll[0] * 255; + colb[1] = coll[1] * 255; + colb[2] = coll[2] * 255; + colb[3] = 255; + + RB_AddQuadStamp( origin, vec1, vec2, colb ); RB_EndSurface(); // back to normal depth range diff --git a/code/renderer_oa/tr_surface.c b/code/renderer_oa/tr_surface.c index 7d4eb538e9..730a684d45 100644 --- a/code/renderer_oa/tr_surface.c +++ b/code/renderer_oa/tr_surface.c @@ -853,6 +853,8 @@ static void LerpMeshVertexes(md3Surface_t *surf, float backlerp) #endif // idppc_altivec LerpMeshVertexes_scalar( surf, backlerp ); } +extern float ProjectRadius( float r, vec3_t location ); + /* ============= @@ -874,6 +876,22 @@ static void RB_SurfaceMesh(md3Surface_t *surface) { backlerp = backEnd.currentEntity->e.backlerp; } + if (r_lerpbias->integer) + { + float projectedRadius, fsh, lerpscale, radius; + trRefEntity_t *ent = backEnd.currentEntity; + fsh = 1; + radius = 1; + lerpscale = r_lerpbias->value*-0.2; + if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) + { + fsh = 1.0f - projectedRadius * lerpscale; + } + if (fsh > 1) + backlerp = 0; + } + + RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles*3 ); LerpMeshVertexes (surface, backlerp); @@ -1299,7 +1317,9 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { (void(*)(void*))RB_SurfacePolychain, // SF_POLY, (void(*)(void*))RB_SurfaceMesh, // SF_MD3, (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR, +#ifdef BROKEN_IQM (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, +#endif (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY (void(*)(void*))RB_SurfaceDisplayList // SF_DISPLAY_LIST diff --git a/code/renderercommon/tr_common.h b/code/renderercommon/tr_common.h index 749f57d5c3..37f65620df 100644 --- a/code/renderercommon/tr_common.h +++ b/code/renderercommon/tr_common.h @@ -47,6 +47,26 @@ typedef enum IMGFLAG_GENNORMALMAP = 0x0100, } imgFlags_t; +// DDS stuff + + +typedef enum +{ + FT_DEFAULT, + FT_LINEAR, + FT_NEAREST +} filterType_t; + +typedef enum +{ + WT_REPEAT, + WT_CLAMP, // don't repeat the texture for texture coords outside [0, 1] + WT_EDGE_CLAMP, + WT_ZERO_CLAMP, // guarantee 0,0,0,255 edge for projected textures + WT_ALPHA_ZERO_CLAMP // guarante 0 alpha edge for projected textures +} wrapType_t; + + typedef struct image_s { char imgName[MAX_QPATH]; // game path, including extension int width, height; // source image @@ -67,6 +87,11 @@ typedef struct image_s { float loadTime; // leilei - time taken loading image float procTime; // leilei - time taken processing image/uploading to vram + + // DXT/DDS stuff + GLenum ddsType; + filterType_t filterType; + wrapType_t wrapType; } image_t; // any change in the LIGHTMAP_* defines here MUST be reflected in diff --git a/code/renderercommon/tr_image_dds.c b/code/renderercommon/tr_image_dds.c new file mode 100644 index 0000000000..9fa7f27b29 --- /dev/null +++ b/code/renderercommon/tr_image_dds.c @@ -0,0 +1,765 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. +Copyright (C) 2007 HermitWorks Entertainment Corporation +Copyright (C) 2006-2009 Robert Beckebans + +This file is part of XreaL source code. + +XreaL source code 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. + +XreaL source code 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 XreaL source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// +// leilei - this is altered a bit from the usual XreaL/Space Trader image_dds +// +// - Removed depth and cubemap stuff as that is not relevant to our spec (we just want faster textures in less bits) +// - Removed software decoding (patent concerns even if it's expired by now) +// +// TODO: +// - Non-square textures don't get uploaded properly!!! +// - DXT3/5 are not handled properly for alpha support. +// - backport LadyHavoc's halfsize-decoding from Darkplaces +// - figure out why the x.org turks driver fails with this. +// +// +// Because it's super incomplete, i'm shoving it in a define. +// +#ifdef BROKEN_DDS +#include "qgl.h" +#include "../renderer_oa/tr_local.h" + +//extern void (APIENTRY * qglColorTableEXT)( GLint, GLint, GLint, GLint, GLint, const GLvoid); +//extern void (APIENTRY * qglColorTableSGI)( GLint, GLint, GLint, GLint, GLint, const GLvoid); +//extern void (APIENTRY * qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); + +typedef struct +{ + unsigned int dwColorSpaceLowValue; // low boundary of color space that is to + // be treated as Color Key, inclusive + + unsigned int dwColorSpaceHighValue; // high boundary of color space that is + // to be treated as Color Key, inclusive +} DDCOLORKEY_t; + +typedef struct +{ + unsigned int dwCaps; // capabilities of surface wanted + unsigned int dwCaps2; + unsigned int dwCaps3; + union + { + unsigned int dwCaps4; + unsigned int dwVolumeDepth; + } u0; +} DDSCAPS2_t; + +typedef struct +{ + unsigned int dwSize; // size of structure + unsigned int dwFlags; // pixel format flags + unsigned int dwFourCC; // (FOURCC code) + + union + { + unsigned int dwRGBBitCount; // how many bits per pixel + unsigned int dwYUVBitCount; // how many bits per pixel + unsigned int dwZBufferBitDepth; // how many total bits/pixel in z buffer (including any stencil bits) + unsigned int dwAlphaBitDepth; // how many bits for alpha channels + unsigned int dwLuminanceBitCount; // how many bits per pixel + unsigned int dwBumpBitCount; // how many bits per "buxel", total + unsigned int dwPrivateFormatBitCount; // Bits per pixel of private driver formats. Only valid in texture + // format list and if DDPF_D3DFORMAT is set + } u0; + + union + { + unsigned int dwRBitMask; // mask for red bit + unsigned int dwYBitMask; // mask for Y bits + unsigned int dwStencilBitDepth; // how many stencil bits (note: dwZBufferBitDepth-dwStencilBitDepth is total Z-only bits) + unsigned int dwLuminanceBitMask; // mask for luminance bits + unsigned int dwBumpDuBitMask; // mask for bump map U delta bits + unsigned int dwOperations; // DDPF_D3DFORMAT Operations + } u1; + + union + { + unsigned int dwGBitMask; // mask for green bits + unsigned int dwUBitMask; // mask for U bits + unsigned int dwZBitMask; // mask for Z bits + unsigned int dwBumpDvBitMask; // mask for bump map V delta bits + struct + { + unsigned short wFlipMSTypes; // Multisample methods supported via flip for this D3DFORMAT + unsigned short wBltMSTypes; // Multisample methods supported via blt for this D3DFORMAT + } MultiSampleCaps; + + } u2; + + union + { + unsigned int dwBBitMask; // mask for blue bits + unsigned int dwVBitMask; // mask for V bits + unsigned int dwStencilBitMask; // mask for stencil bits + unsigned int dwBumpLuminanceBitMask; // mask for luminance in bump map + } u3; + + union + { + unsigned int dwRGBAlphaBitMask; // mask for alpha channel + unsigned int dwYUVAlphaBitMask; // mask for alpha channel + unsigned int dwLuminanceAlphaBitMask; // mask for alpha channel + unsigned int dwRGBZBitMask; // mask for Z channel + unsigned int dwYUVZBitMask; // mask for Z channel + } u4; +} DDPIXELFORMAT_t; + +typedef struct +{ + unsigned int dwSize; // size of the DDSURFACEDESC structure + unsigned int dwFlags; // determines what fields are valid + unsigned int dwHeight; // height of surface to be created + unsigned int dwWidth; // width of input surface + + union + { + int lPitch; // distance to start of next line (return value only) + unsigned int dwLinearSize; // Formless late-allocated optimized surface size + } u0; + + union + { + unsigned int dwBackBufferCount; // number of back buffers requested + unsigned int dwDepth; // the depth if this is a volume texture + } u1; + + union + { + unsigned int dwMipMapCount; // number of mip-map levels requestde + // dwZBufferBitDepth removed, use ddpfPixelFormat one instead + unsigned int dwRefreshRate; // refresh rate (used when display mode is described) + unsigned int dwSrcVBHandle; // The source used in VB::Optimize + } u2; + + unsigned int dwAlphaBitDepth; // depth of alpha buffer requested + unsigned int dwReserved; // reserved + void *lpSurface; // pointer to the associated surface memory + + union + { + DDCOLORKEY_t ddckCKDestOverlay; // color key for destination overlay use + unsigned int dwEmptyFaceColor; // Physical color for empty cubemap faces + } u3; + DDCOLORKEY_t ddckCKDestBlt; // color key for destination blt use + DDCOLORKEY_t ddckCKSrcOverlay; // color key for source overlay use + DDCOLORKEY_t ddckCKSrcBlt; // color key for source blt use + union + { + DDPIXELFORMAT_t ddpfPixelFormat; // pixel format description of the surface + unsigned int dwFVF; // vertex format description of vertex buffers + } u4; + DDSCAPS2_t ddsCaps; // direct draw surface capabilities + unsigned int dwTextureStage; // stage in multitexture cascade +} DDSURFACEDESC2_t; + +// +// DDSURFACEDESC2 flags that mark the validity of the struct data +// +#define DDSD_CAPS 0x00000001l // default +#define DDSD_HEIGHT 0x00000002l // default +#define DDSD_WIDTH 0x00000004l // default +#define DDSD_PIXELFORMAT 0x00001000l // default +#define DDSD_PITCH 0x00000008l // For uncompressed formats +#define DDSD_MIPMAPCOUNT 0x00020000l +#define DDSD_LINEARSIZE 0x00080000l // For compressed formats +#define DDSD_DEPTH 0x00800000l // Volume Textures + +// +// DDPIXELFORMAT flags +// +#define DDPF_ALPHAPIXELS 0x00000001l +#define DDPF_FOURCC 0x00000004l // Compressed formats +#define DDPF_RGB 0x00000040l // Uncompressed formats +#define DDPF_ALPHA 0x00000002l +#define DDPF_COMPRESSED 0x00000080l +#define DDPF_LUMINANCE 0x00020000l +#define DDPF_PALETTEINDEXED4 0x00000008l +#define DDPF_PALETTEINDEXEDTO8 0x00000010l +#define DDPF_PALETTEINDEXED8 0x00000020l + +// +// DDSCAPS flags +// +#define DDSCAPS_COMPLEX 0x00000008l +#define DDSCAPS_TEXTURE 0x00001000l // default +#define DDSCAPS_MIPMAP 0x00400000l + +#define DDSCAPS2_VOLUME 0x00200000l +#define DDSCAPS2_CUBEMAP 0x00000200L +#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400L +#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800L +#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000L +#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000L +#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000L +#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000L + +#ifndef MAKEFOURCC + +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((unsigned int)(char)(ch0) | ((unsigned int)(char)(ch1) << 8) | \ + ((unsigned int)(char)(ch2) << 16) | ((unsigned int)(char)(ch3) << 24 )) + +#endif + +#define FOURCC_DDS MAKEFOURCC( 'D', 'D', 'S', ' ' ) + +//FOURCC codes for DXTn compressed-texture pixel formats +#define FOURCC_DXT1 MAKEFOURCC( 'D', 'X', 'T', '1' ) +#define FOURCC_DXT2 MAKEFOURCC( 'D', 'X', 'T', '2' ) +#define FOURCC_DXT3 MAKEFOURCC( 'D', 'X', 'T', '3' ) +#define FOURCC_DXT4 MAKEFOURCC( 'D', 'X', 'T', '4' ) +#define FOURCC_DXT5 MAKEFOURCC( 'D', 'X', 'T', '5' ) + +#define R_LoadDDSImage_MAX_MIPS 16 + + +int swdecode = 0; // not really working + +static void R_UploadCompressedImage2D(image_t * img, GLenum target, int level, GLenum format, int width, int height, int size, + const void *data) +{ + GLenum int_fmat; + + //if(glConfig.textureCompression == TC_S3TC) + + if (!swdecode) + { + qglCompressedTexImage2DARB(target, level, format, width, height, 0, size, data); + + return; + } + else + { + + + // nothing atol + + } + + // leilei - software decoding is ALL STRIPPED!!! Not only for simplicity, + // but there is a patent issue regarding the decoding. + // So, we only support DDS textures though directly + // using the driver itself to upload and don't even try to decode + // any of it. Not even for a lousy PowerVR alpha hack. + // Besides. the intent is to get those old dmm maps working + // as intended. I don't really have big plans for DDS. +} + +static void R_UploadImage2D(image_t * img, GLenum target, int level, GLenum int_fmat, + int width, int height, GLenum format, GLenum type, const void *data) +{ + + + qglTexImage2D(target, level, int_fmat, width, height, 0, format, type, data); +} +extern image_t *R_AllocImage(const char *name, qboolean linkIntoHashTable); + +image_t *R_LoadDDSImageData(void *pImageData, const char *name, int bits, filterType_t filterType, wrapType_t wrapType) +{ + image_t *ret = NULL; + + byte *buff; + + DDSURFACEDESC2_t *ddsd; //used to get at the dds header in the read buffer + + //based on texture type: + // cube width != 0, height == 0, depth == 0 + // 2D width != 0, height != 0, depth == 0 + // volume width != 0, height != 0, depth != 0 + int width, height, depth; + + //mip count and pointers to image data for each mip + //level, idx 0 = top level last pointer does not start + //a mip level, it's just there to mark off the end of + //the final mip data segment (thus the odd + 1) + // + //for cube textures we only find the offsets into the + //first face of the cube, subsequent faces will use the + //same offsets, just shifted over + int mipLevels; + byte *mipOffsets[R_LoadDDSImage_MAX_MIPS + 1]; + + qboolean usingAlpha; + + qboolean compressed; + GLuint format = 0; + GLuint internal_format = 0; + GLenum type = GL_UNSIGNED_BYTE; + + vec4_t zeroClampBorder = { 0, 0, 0, 1 }; + vec4_t alphaZeroClampBorder = { 0, 0, 0, 0 }; + + //comes from R_CreateImage + + + buff = (byte *) pImageData; + + if(strncmp((const char *)buff, "DDS ", 4) != 0) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: invalid dds header \"%s\"\n", name); + goto ret_error; + } + + ddsd = (DDSURFACEDESC2_t *) (buff + 4); + + if(ddsd->dwSize != sizeof(DDSURFACEDESC2_t) || ddsd->u4.ddpfPixelFormat.dwSize != sizeof(DDPIXELFORMAT_t)) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: invalid dds header \"%s\"\n", name); + goto ret_error; + } + + usingAlpha = (ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) ? qtrue : qfalse; + mipLevels = ((ddsd->dwFlags & DDSD_MIPMAPCOUNT) && (ddsd->u2.dwMipMapCount > 1)) ? ddsd->u2.dwMipMapCount : 1; + + if(mipLevels > R_LoadDDSImage_MAX_MIPS) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: dds image has too many mip levels \"%s\"\n", name); + goto ret_error; + } + + compressed = (ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) ? qtrue : qfalse; + + // either a cube or a volume + if(ddsd->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP) + { + // cube texture + + if(ddsd->dwWidth != ddsd->dwHeight) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: invalid dds image \"%s\"\n", name); + goto ret_error; + } + + width = ddsd->dwWidth; + height = 0; + depth = 0; + + if(width & (width - 1)) + { + //cubes must be a power of two + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: cube images must be power of two \"%s\"\n", name); + goto ret_error; + } + } + else if((ddsd->ddsCaps.dwCaps2 & DDSCAPS2_VOLUME) && (ddsd->dwFlags & DDSD_DEPTH)) + { + // 3D texture + + width = ddsd->dwWidth; + height = ddsd->dwHeight; + depth = ddsd->u1.dwDepth; + + if(width & (width - 1) || height & (height - 1) || depth & (depth - 1)) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: volume images must be power of two \"%s\"\n", name); + goto ret_error; + } + } + else + { + // 2D texture + + width = ddsd->dwWidth; + height = ddsd->dwHeight; + depth = 0; + + //these are allowed to be non power of two, will be dealt with later on + //except for compressed images! + if(compressed && (width & (width - 1) || height & (height - 1))) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: compressed texture images must be power of two \"%s\"\n", name); + goto ret_error; + } + } + + if(compressed) + { + int blockSize; + + if(depth != 0) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: compressed volume textures are not supported \"%s\"\n", name); + goto ret_error; + } + + //compressed FOURCC formats + switch (ddsd->u4.ddpfPixelFormat.dwFourCC) + { + case FOURCC_DXT1: + blockSize = 8; + usingAlpha = qtrue; + format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + + case FOURCC_DXT3: + blockSize = 16; + usingAlpha = qtrue; + format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + + case FOURCC_DXT5: + blockSize = 16; + usingAlpha = qtrue; + format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + + default: + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: unsupported FOURCC \"%s\", \"%s\"\n", + &ddsd->u4.ddpfPixelFormat.dwFourCC, name); + goto ret_error; + } + + //get mip offsets + if(format) + { + int w = width; + int h = height; + int offset = 0; + int i; + + if(h == 0) + h = w; //cube map + + for(i = 0; (i < mipLevels) && (w || h); i++) + { + int qw, qh; + + mipOffsets[i] = buff + 4 + sizeof(DDSURFACEDESC2_t) + offset; + + if(w == 0) + w = 1; + if(h == 0) + h = 1; + + //size formula comes from DX docs (August 2005 SDK reference) + qw = w >> 2; + if(qw == 0) + qw = 1; + qh = h >> 2; + if(qh == 0) + qh = 1; + + offset += qw * qh * blockSize; + + w >>= 1; + h >>= 1; + } + + //put in the trailing offset + mipOffsets[i] = buff + 4 + sizeof(DDSURFACEDESC2_t) + offset; + } + else + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: error reading DDS image \"%s\"\n", name); + goto ret_error; + } + + internal_format = format; + } + else + { + // uncompressed format + if(ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_RGB) + { + switch (ddsd->u4.ddpfPixelFormat.u0.dwRGBBitCount) + { + case 32: + internal_format = usingAlpha ? GL_RGBA8 : GL_RGB8; + format = GL_BGRA_EXT; + break; + + case 24: + internal_format = GL_RGB8; + format = GL_BGR_EXT; + break; + + case 16: + if(usingAlpha) + { + //must be A1R5G5B5 + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: unsupported format, 5551 \"%s\"\n", name); + goto ret_error; + } + else + { + //find out if it's X1R5G5B5 or R5G6B5 + + internal_format = GL_RGB5; + format = GL_RGB; + + if(ddsd->u4.ddpfPixelFormat.u2.dwGBitMask == 0x7E0) + type = GL_UNSIGNED_SHORT_5_6_5; + else + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: unsupported format, 5551 \"%s\"\n", name); + goto ret_error; + } + } + break; + + default: + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: unsupported RGB bit depth \"%s\"\n", name); + goto ret_error; + } + } + else if(ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_LUMINANCE) + { + internal_format = usingAlpha ? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE8; + format = usingAlpha ? GL_LUMINANCE_ALPHA : GL_LUMINANCE; + } + else if(ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_ALPHA) + { + internal_format = GL_ALPHA8; + format = GL_ALPHA; + } + else if(ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + { + internal_format = usingAlpha ? GL_RGB5_A1 : GL_RGB5; + format = GL_COLOR_INDEX4_EXT; + } + else if(ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + { + internal_format = usingAlpha ? GL_RGBA : GL_RGB; + format = GL_COLOR_INDEX8_EXT; + } + else + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: unsupported DDS image type \"%s\"\n", name); + goto ret_error; + } + + if(format) + { + int offset = 0; + int w = width; + int h = height; + int d = depth; + int i; + + if(h == 0) + h = w; //cube map + + for(i = 0; (i < mipLevels) && (w || h || d); i++) + { + mipOffsets[i] = buff + 4 + sizeof(DDSURFACEDESC2_t) + offset; + + if(w == 0) + w = 1; + if(h == 0) + h = 1; + if(d == 0) + d = 1; + + offset += (w * h * d * (ddsd->u4.ddpfPixelFormat.u0.dwRGBBitCount / 8)); + + w >>= 1; + h >>= 1; + d >>= 1; + } + + //put in the trailing offset + mipOffsets[i] = buff + 4 + sizeof(DDSURFACEDESC2_t) + offset; + } + else + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: Unexpected error reading DDS image \"%s\"\n", name); + goto ret_error; + } + } + + //we now have a full description of our image set up + //if we fail after this point we still want our image_t + //record in the hash so that we don't go trying to read + //the file again - been printing an error and returning + //NULL up to this point... + ret = R_AllocImage(name, qtrue); + + ret->uploadWidth = ret->width = width; + ret->uploadHeight = ret->height = height; + + ret->internalFormat = internal_format; + + ret->filterType = ((filterType == FT_DEFAULT) && (mipLevels > 1)) ? FT_DEFAULT : FT_LINEAR; + + if(ret->filterType == FT_LINEAR) + mipLevels = 1; + + // leilei - we do not support depth or cubemaps. + + { + // planar texture + + int w = width; + int h = height; + + int i; + + GLuint texnum; + + if(w & (w - 1) || h & (h - 1)) + { + // non-pow2: check extensions + + // if(glConfig.textureNPOTAvailable) + // { + // ret->type = GL_TEXTURE_2D; + // } + // else + { + ret->type = GL_TEXTURE_2D; // FIXME R_StateGetRectTarget(); + } + } + else + { + ret->type = GL_TEXTURE_2D; + } + + texnum = ret->texnum; + + if (w != h){ // leilei - rectangle texture hack + //ret->type = GL_TEXTURE_RECTANGLE_ARB; + h = w; + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: uploading %s, %i x %i\n", ret, w, h); + } + + GL_Bind(ret); + + if(mipLevels == 1) + qglTexParameteri(ret->type, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); + + for(i = 0; i < mipLevels; i++) + { + if(compressed) + { + GLsizei size = mipOffsets[i + 1] - mipOffsets[i]; + R_UploadCompressedImage2D(ret, ret->type, i, internal_format, w, h, size, mipOffsets[i]); + } + else + { + R_UploadImage2D(ret, ret->type, i, internal_format, w, h, format, type, mipOffsets[i]); + } + + w >>= 1; + if(w == 0) + w = 1; + h >>= 1; + if(h == 0) + h = 1; + } + } + + + GL_CheckErrors(); + + // set filter type + ret->filterType = filterType; + + // who cares about filtertype? + if(textureFilterAnisotropic) + qglTexParameterf(ret->type, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_ext_texture_filter_anisotropic->value); + + qglTexParameterf(ret->type, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTexParameterf(ret->type, GL_TEXTURE_MAG_FILTER, gl_filter_max); + + GL_CheckErrors(); + + // set wrap type + // we do care about this though. bouncepads etc + ret->wrapType = wrapType; + + switch (wrapType) + { + case WT_REPEAT: + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_REPEAT); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + + case WT_CLAMP: + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_CLAMP); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_CLAMP); + break; + + case WT_EDGE_CLAMP: + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + break; + + case WT_ZERO_CLAMP: + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + qglTexParameterfv(ret->type, GL_TEXTURE_BORDER_COLOR, zeroClampBorder); + break; + + case WT_ALPHA_ZERO_CLAMP: + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + qglTexParameterfv(ret->type, GL_TEXTURE_BORDER_COLOR, alphaZeroClampBorder); + break; + + default: + ri.Printf(PRINT_WARNING, "WARNING: unknown wrap type for image '%s'\n", ret->imgName); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_REPEAT); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + } + + + GL_CheckErrors(); + + //GL_Unbind(); + qglBindTexture(ret->type, 0); + + ret_error: + return ret; +} + + +image_t *R_LoadDDSImage(const char *name, int bits, filterType_t filterType, wrapType_t wrapType) +{ + image_t *ret; + byte *buff; + int len; + + // comes from R_CreateImage + /* + if(tr.numImages == MAX_DRAWIMAGES) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: MAX_DRAWIMAGES hit\n"); + return NULL; + } + */ + + len = ri.FS_ReadFile(name, (void **)&buff); + if(!buff) + return 0; + + ret = R_LoadDDSImageData(buff, name, bits, filterType, wrapType); + + ri.FS_FreeFile(buff); + + return ret; +} + +#endif // BROKEN_DDS \ No newline at end of file diff --git a/code/renderercommon/tr_public.h b/code/renderercommon/tr_public.h index bc00c779f9..edcc9fedc3 100644 --- a/code/renderercommon/tr_public.h +++ b/code/renderercommon/tr_public.h @@ -70,6 +70,7 @@ typedef struct { void (*RenderScene)( const refdef_t *fd ); void (*LFX_ParticleEffect)( int effect, const vec3_t origin, const vec3_t velocity ); // leilei - particles + void (*GetViewPosition)( vec3_t point ); void (*SetColor)( const float *rgba ); // NULL = 1,1,1,1 void (*DrawStretchPic) ( float x, float y, float w, float h, diff --git a/code/renderercommon/tr_types.h b/code/renderercommon/tr_types.h index 0f382ba551..c70a6078f6 100644 --- a/code/renderercommon/tr_types.h +++ b/code/renderercommon/tr_types.h @@ -122,6 +122,10 @@ typedef struct { vec3_t eyepos[2]; // looking from vec3_t eyelook; // looking from + // leilei - glow + + int glow; // glow security + fx + int glowcol; // glow color in hexadecimal } refEntity_t; diff --git a/code/renderergl1/tr_animation.c b/code/renderergl1/tr_animation.c deleted file mode 100644 index 7bcc5bdf69..0000000000 --- a/code/renderergl1/tr_animation.c +++ /dev/null @@ -1,521 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -/* - -All bones should be an identity orientation to display the mesh exactly -as it is specified. - -For all other frames, the bones represent the transformation from the -orientation of the bone in the base frame to the orientation in this -frame. - -*/ - - -// copied and adapted from tr_mesh.c - -/* -============= -R_MDRCullModel -============= -*/ - -static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) { - vec3_t bounds[2]; - mdrFrame_t *oldFrame, *newFrame; - int i, frameSize; - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - // compute frame pointers - newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe); - - // cull bounding sphere ONLY if this is not an upscaled entity - if ( !ent->e.nonNormalizedAxes ) - { - if ( ent->e.frame == ent->e.oldframe ) - { - switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) - { - // Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend - // we do. After all, the purpose of mdrs are not that different, are they? - - case CULL_OUT: - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - - case CULL_IN: - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - - case CULL_CLIP: - tr.pc.c_sphere_cull_md3_clip++; - break; - } - } - else - { - int sphereCull, sphereCullB; - - sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); - if ( newFrame == oldFrame ) { - sphereCullB = sphereCull; - } else { - sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); - } - - if ( sphereCull == sphereCullB ) - { - if ( sphereCull == CULL_OUT ) - { - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - } - else if ( sphereCull == CULL_IN ) - { - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - } - else - { - tr.pc.c_sphere_cull_md3_clip++; - } - } - } - } - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; - bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - -/* -================= -R_MDRComputeFogNum - -================= -*/ - -int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - mdrFrame_t *mdrFrame; - vec3_t localOrigin; - int frameSize; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - // FIXME: non-normalized axis issues - mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin ); - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - - -/* -============== -R_MDRAddAnimSurfaces -============== -*/ - -// much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c - -void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { - mdrHeader_t *header; - mdrSurface_t *surface; - mdrLOD_t *lod; - shader_t *shader; - skin_t *skin; - int i, j; - int lodnum = 0; - int fogNum = 0; - int cull; - qboolean personalModel; - - header = (mdrHeader_t *) tr.currentModel->modelData; - - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) - { - ent->e.frame %= header->numFrames; - ent->e.oldframe %= header->numFrames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ((ent->e.frame >= header->numFrames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= header->numFrames) - || (ent->e.oldframe < 0) ) - { - ri.Printf( PRINT_DEVELOPER, "R_MDRAddAnimSurfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_MDRCullModel (header, ent); - if ( cull == CULL_OUT ) { - return; - } - - // figure out the current LOD of the model we're rendering, and set the lod pointer respectively. - lodnum = R_ComputeLOD(ent); - // check whether this model has as that many LODs at all. If not, try the closest thing we got. - if(header->numLODs <= 0) - return; - if(header->numLODs <= lodnum) - lodnum = header->numLODs - 1; - - lod = (mdrLOD_t *)( (byte *)header + header->ofsLODs); - for(i = 0; i < lodnum; i++) - { - lod = (mdrLOD_t *) ((byte *) lod + lod->ofsEnd); - } - - // set up lighting - if ( !personalModel || r_shadows->integer > 1 ) - { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // fogNum? - fogNum = R_MDRComputeFogNum( header, ent ); - - surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces ); - - for ( i = 0 ; i < lod->numSurfaces ; i++ ) - { - - if(ent->e.customShader) - shader = R_GetShaderByHandle(ent->e.customShader); - else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) - { - skin = R_GetSkinByHandle(ent->e.customSkin); - shader = tr.defaultShader; - - for(j = 0; j < skin->numSurfaces; j++) - { - if (!strcmp(skin->surfaces[j]->name, surface->name)) - { - shader = skin->surfaces[j]->shader; - break; - } - } - } - else if(surface->shaderIndex > 0) - shader = R_GetShaderByHandle( surface->shaderIndex ); - else - shader = tr.defaultShader; - - // we will add shadows even if the main object isn't visible in the view - - // stencil shadows can't do personal models unless I polyhedron clip - if ( !personalModel - && r_shadows->integer == 2 - && fogNum == 0 - && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) - && shader->sort == SS_OPAQUE ) - { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse ); - } - - // projection shadows work fine with personal models - if ( r_shadows->integer == 3 - && fogNum == 0 - && (ent->e.renderfx & RF_SHADOW_PLANE ) - && shader->sort == SS_OPAQUE ) - { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse ); - } - - if (!personalModel) - R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse ); - - surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd ); - } -} - -/* -============== -RB_MDRSurfaceAnim -============== -*/ -void RB_MDRSurfaceAnim( mdrSurface_t *surface ) -{ - int i, j, k; - float frontlerp, backlerp; - int *triangles; - int indexes; - int baseIndex, baseVertex; - int numVerts; - mdrVertex_t *v; - mdrHeader_t *header; - mdrFrame_t *frame; - mdrFrame_t *oldFrame; - mdrBone_t bones[MDR_MAX_BONES], *bonePtr, *bone; - - int frameSize; - - // don't lerp if lerping off, or this is the only frame, or the last frame... - // - if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame) - { - backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used - frontlerp = 1; - } - else - { - backlerp = backEnd.currentEntity->e.backlerp; - frontlerp = 1.0f - backlerp; - } - - header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader); - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - frame = (mdrFrame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.frame * frameSize ); - oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.oldframe * frameSize ); - - RB_CheckOverflow( surface->numVerts, surface->numTriangles ); - - triangles = (int *) ((byte *)surface + surface->ofsTriangles); - indexes = surface->numTriangles * 3; - baseIndex = tess.numIndexes; - baseVertex = tess.numVertexes; - - // Set up all triangles. - for (j = 0 ; j < indexes ; j++) - { - tess.indexes[baseIndex + j] = baseVertex + triangles[j]; - } - tess.numIndexes += indexes; - - // - // lerp all the needed bones - // - if ( !backlerp ) - { - // no lerping needed - bonePtr = frame->bones; - } - else - { - bonePtr = bones; - - for ( i = 0 ; i < header->numBones*12 ; i++ ) - { - ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i]; - } - } - - // - // deform the vertexes by the lerped bones - // - numVerts = surface->numVerts; - v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts); - for ( j = 0; j < numVerts; j++ ) - { - vec3_t tempVert, tempNormal; - mdrWeight_t *w; - - VectorClear( tempVert ); - VectorClear( tempNormal ); - w = v->weights; - for ( k = 0 ; k < v->numWeights ; k++, w++ ) - { - bone = bonePtr + w->boneIndex; - - tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] ); - tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] ); - tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] ); - - tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal ); - tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal ); - tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal ); - } - - tess.xyz[baseVertex + j][0] = tempVert[0]; - tess.xyz[baseVertex + j][1] = tempVert[1]; - tess.xyz[baseVertex + j][2] = tempVert[2]; - - tess.normal[baseVertex + j][0] = tempNormal[0]; - tess.normal[baseVertex + j][1] = tempNormal[1]; - tess.normal[baseVertex + j][2] = tempNormal[2]; - - tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; - tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; - - v = (mdrVertex_t *)&v->weights[v->numWeights]; - } - - tess.numVertexes += surface->numVerts; -} - - -#define MC_MASK_X ((1<<(MC_BITS_X))-1) -#define MC_MASK_Y ((1<<(MC_BITS_Y))-1) -#define MC_MASK_Z ((1<<(MC_BITS_Z))-1) -#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1) - -#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2)) - -#define MC_POS_X (0) -#define MC_SHIFT_X (0) - -#define MC_POS_Y ((((MC_BITS_X))/8)) -#define MC_SHIFT_Y ((((MC_BITS_X)%8))) - -#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8)) -#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8))) - -#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8)) -#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8))) - -#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8)) -#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8))) - -#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8)) -#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8))) - -#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8)) -#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8))) - -#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8)) -#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8))) - -#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8)) -#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8))) - -#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8)) -#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8))) - -#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8)) -#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8))) - -#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8)) -#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8))) - -void MC_UnCompress(float mat[3][4],const unsigned char * comp) -{ - int val; - - val=(int)((unsigned short *)(comp))[0]; - val-=1<<(MC_BITS_X-1); - mat[0][3]=((float)(val))*MC_SCALE_X; - - val=(int)((unsigned short *)(comp))[1]; - val-=1<<(MC_BITS_Y-1); - mat[1][3]=((float)(val))*MC_SCALE_Y; - - val=(int)((unsigned short *)(comp))[2]; - val-=1<<(MC_BITS_Z-1); - mat[2][3]=((float)(val))*MC_SCALE_Z; - - val=(int)((unsigned short *)(comp))[3]; - val-=1<<(MC_BITS_VECT-1); - mat[0][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[4]; - val-=1<<(MC_BITS_VECT-1); - mat[0][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[5]; - val-=1<<(MC_BITS_VECT-1); - mat[0][2]=((float)(val))*MC_SCALE_VECT; - - - val=(int)((unsigned short *)(comp))[6]; - val-=1<<(MC_BITS_VECT-1); - mat[1][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[7]; - val-=1<<(MC_BITS_VECT-1); - mat[1][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[8]; - val-=1<<(MC_BITS_VECT-1); - mat[1][2]=((float)(val))*MC_SCALE_VECT; - - - val=(int)((unsigned short *)(comp))[9]; - val-=1<<(MC_BITS_VECT-1); - mat[2][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[10]; - val-=1<<(MC_BITS_VECT-1); - mat[2][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[11]; - val-=1<<(MC_BITS_VECT-1); - mat[2][2]=((float)(val))*MC_SCALE_VECT; -} diff --git a/code/renderergl1/tr_backend.c b/code/renderergl1/tr_backend.c deleted file mode 100644 index 0a3fe03628..0000000000 --- a/code/renderergl1/tr_backend.c +++ /dev/null @@ -1,1166 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -backEndData_t *backEndData; -backEndState_t backEnd; - - -static float s_flipMatrix[16] = { - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 -}; - - -/* -** GL_Bind -*/ -void GL_Bind( image_t *image ) { - int texnum; - - if ( !image ) { - ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" ); - texnum = tr.defaultImage->texnum; - } else { - texnum = image->texnum; - } - - if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option - texnum = tr.dlightImage->texnum; - } - - if ( glState.currenttextures[glState.currenttmu] != texnum ) { - if ( image ) { - image->frameUsed = tr.frameCount; - } - glState.currenttextures[glState.currenttmu] = texnum; - qglBindTexture (GL_TEXTURE_2D, texnum); - } -} - -/* -** GL_SelectTexture -*/ -void GL_SelectTexture( int unit ) -{ - if ( glState.currenttmu == unit ) - { - return; - } - - if ( unit == 0 ) - { - qglActiveTextureARB( GL_TEXTURE0_ARB ); - GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE0_ARB )\n" ); - qglClientActiveTextureARB( GL_TEXTURE0_ARB ); - GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE0_ARB )\n" ); - } - else if ( unit == 1 ) - { - qglActiveTextureARB( GL_TEXTURE1_ARB ); - GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE1_ARB )\n" ); - qglClientActiveTextureARB( GL_TEXTURE1_ARB ); - GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE1_ARB )\n" ); - } else { - ri.Error( ERR_DROP, "GL_SelectTexture: unit = %i", unit ); - } - - glState.currenttmu = unit; -} - - -/* -** GL_BindMultitexture -*/ -void GL_BindMultitexture( image_t *image0, GLuint env0, image_t *image1, GLuint env1 ) { - int texnum0, texnum1; - - texnum0 = image0->texnum; - texnum1 = image1->texnum; - - if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option - texnum0 = texnum1 = tr.dlightImage->texnum; - } - - if ( glState.currenttextures[1] != texnum1 ) { - GL_SelectTexture( 1 ); - image1->frameUsed = tr.frameCount; - glState.currenttextures[1] = texnum1; - qglBindTexture( GL_TEXTURE_2D, texnum1 ); - } - if ( glState.currenttextures[0] != texnum0 ) { - GL_SelectTexture( 0 ); - image0->frameUsed = tr.frameCount; - glState.currenttextures[0] = texnum0; - qglBindTexture( GL_TEXTURE_2D, texnum0 ); - } -} - - -/* -** GL_Cull -*/ -void GL_Cull( int cullType ) { - if ( glState.faceCulling == cullType ) { - return; - } - - glState.faceCulling = cullType; - - if ( cullType == CT_TWO_SIDED ) - { - qglDisable( GL_CULL_FACE ); - } - else - { - qboolean cullFront; - qglEnable( GL_CULL_FACE ); - - cullFront = (cullType == CT_FRONT_SIDED); - if ( backEnd.viewParms.isMirror ) - { - cullFront = !cullFront; - } - - qglCullFace( cullFront ? GL_FRONT : GL_BACK ); - } -} - -/* -** GL_TexEnv -*/ -void GL_TexEnv( int env ) -{ - if ( env == glState.texEnv[glState.currenttmu] ) - { - return; - } - - glState.texEnv[glState.currenttmu] = env; - - - switch ( env ) - { - case GL_MODULATE: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - break; - case GL_REPLACE: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); - break; - case GL_DECAL: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); - break; - case GL_ADD: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD ); - break; - default: - ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed", env ); - break; - } -} - -/* -** GL_State -** -** This routine is responsible for setting the most commonly changed state -** in Q3. -*/ -void GL_State( unsigned long stateBits ) -{ - unsigned long diff = stateBits ^ glState.glStateBits; - - if ( !diff ) - { - return; - } - - // - // check depthFunc bits - // - if ( diff & GLS_DEPTHFUNC_EQUAL ) - { - if ( stateBits & GLS_DEPTHFUNC_EQUAL ) - { - qglDepthFunc( GL_EQUAL ); - } - else - { - qglDepthFunc( GL_LEQUAL ); - } - } - - // - // check blend bits - // - if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) - { - GLenum srcFactor = GL_ONE, dstFactor = GL_ONE; - - if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) - { - switch ( stateBits & GLS_SRCBLEND_BITS ) - { - case GLS_SRCBLEND_ZERO: - srcFactor = GL_ZERO; - break; - case GLS_SRCBLEND_ONE: - srcFactor = GL_ONE; - break; - case GLS_SRCBLEND_DST_COLOR: - srcFactor = GL_DST_COLOR; - break; - case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: - srcFactor = GL_ONE_MINUS_DST_COLOR; - break; - case GLS_SRCBLEND_SRC_ALPHA: - srcFactor = GL_SRC_ALPHA; - break; - case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: - srcFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - case GLS_SRCBLEND_DST_ALPHA: - srcFactor = GL_DST_ALPHA; - break; - case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: - srcFactor = GL_ONE_MINUS_DST_ALPHA; - break; - case GLS_SRCBLEND_ALPHA_SATURATE: - srcFactor = GL_SRC_ALPHA_SATURATE; - break; - default: - ri.Error( ERR_DROP, "GL_State: invalid src blend state bits" ); - break; - } - - switch ( stateBits & GLS_DSTBLEND_BITS ) - { - case GLS_DSTBLEND_ZERO: - dstFactor = GL_ZERO; - break; - case GLS_DSTBLEND_ONE: - dstFactor = GL_ONE; - break; - case GLS_DSTBLEND_SRC_COLOR: - dstFactor = GL_SRC_COLOR; - break; - case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: - dstFactor = GL_ONE_MINUS_SRC_COLOR; - break; - case GLS_DSTBLEND_SRC_ALPHA: - dstFactor = GL_SRC_ALPHA; - break; - case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: - dstFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - case GLS_DSTBLEND_DST_ALPHA: - dstFactor = GL_DST_ALPHA; - break; - case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: - dstFactor = GL_ONE_MINUS_DST_ALPHA; - break; - default: - ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits" ); - break; - } - - qglEnable( GL_BLEND ); - qglBlendFunc( srcFactor, dstFactor ); - } - else - { - qglDisable( GL_BLEND ); - } - } - - // - // check depthmask - // - if ( diff & GLS_DEPTHMASK_TRUE ) - { - if ( stateBits & GLS_DEPTHMASK_TRUE ) - { - qglDepthMask( GL_TRUE ); - } - else - { - qglDepthMask( GL_FALSE ); - } - } - - // - // fill/line mode - // - if ( diff & GLS_POLYMODE_LINE ) - { - if ( stateBits & GLS_POLYMODE_LINE ) - { - qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); - } - else - { - qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - } - } - - // - // depthtest - // - if ( diff & GLS_DEPTHTEST_DISABLE ) - { - if ( stateBits & GLS_DEPTHTEST_DISABLE ) - { - qglDisable( GL_DEPTH_TEST ); - } - else - { - qglEnable( GL_DEPTH_TEST ); - } - } - - // - // alpha test - // - if ( diff & GLS_ATEST_BITS ) - { - switch ( stateBits & GLS_ATEST_BITS ) - { - case 0: - qglDisable( GL_ALPHA_TEST ); - break; - case GLS_ATEST_GT_0: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_GREATER, 0.0f ); - break; - case GLS_ATEST_LT_80: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_LESS, 0.5f ); - break; - case GLS_ATEST_GE_80: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_GEQUAL, 0.5f ); - break; - default: - assert( 0 ); - break; - } - } - - glState.glStateBits = stateBits; -} - - - -/* -================ -RB_Hyperspace - -A player has predicted a teleport, but hasn't arrived yet -================ -*/ -static void RB_Hyperspace( void ) { - float c; - - if ( !backEnd.isHyperspace ) { - // do initialization shit - } - - c = ( backEnd.refdef.time & 255 ) / 255.0f; - qglClearColor( c, c, c, 1 ); - qglClear( GL_COLOR_BUFFER_BIT ); - - backEnd.isHyperspace = qtrue; -} - - -static void SetViewportAndScissor( void ) { - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf( backEnd.viewParms.projectionMatrix ); - qglMatrixMode(GL_MODELVIEW); - - // set the window clipping - qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, - backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); - qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, - backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); -} - -/* -================= -RB_BeginDrawingView - -Any mirrored or portaled views have already been drawn, so prepare -to actually render the visible surfaces for this view -================= -*/ -void RB_BeginDrawingView (void) { - int clearBits = 0; - - // sync with gl if needed - if ( r_finish->integer == 1 && !glState.finishCalled ) { - qglFinish (); - glState.finishCalled = qtrue; - } - if ( r_finish->integer == 0 ) { - glState.finishCalled = qtrue; - } - - // we will need to change the projection matrix before drawing - // 2D images again - backEnd.projection2D = qfalse; - - // - // set the modelview matrix for the viewer - // - SetViewportAndScissor(); - - // ensures that depth writes are enabled for the depth clear - GL_State( GLS_DEFAULT ); - // clear relevant buffers - clearBits = GL_DEPTH_BUFFER_BIT; - - if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) - { - clearBits |= GL_STENCIL_BUFFER_BIT; - } - if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) - { - clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used -#ifdef _DEBUG - qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky -#else - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky -#endif - } - qglClear( clearBits ); - - if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) - { - RB_Hyperspace(); - return; - } - else - { - backEnd.isHyperspace = qfalse; - } - - glState.faceCulling = -1; // force face culling to set next time - - // we will only draw a sun if there was sky rendered in this view - backEnd.skyRenderedThisView = qfalse; - - // clip to the plane of the portal - if ( backEnd.viewParms.isPortal ) { - float plane[4]; - double plane2[4]; - - plane[0] = backEnd.viewParms.portalPlane.normal[0]; - plane[1] = backEnd.viewParms.portalPlane.normal[1]; - plane[2] = backEnd.viewParms.portalPlane.normal[2]; - plane[3] = backEnd.viewParms.portalPlane.dist; - - plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); - plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); - plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); - plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; - - qglLoadMatrixf( s_flipMatrix ); - qglClipPlane (GL_CLIP_PLANE0, plane2); - qglEnable (GL_CLIP_PLANE0); - } else { - qglDisable (GL_CLIP_PLANE0); - } -} - - -#define MAC_EVENT_PUMP_MSEC 5 - -/* -================== -RB_RenderDrawSurfList -================== -*/ -void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { - shader_t *shader, *oldShader; - int fogNum, oldFogNum; - int entityNum, oldEntityNum; - int dlighted, oldDlighted; - qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; - int i; - drawSurf_t *drawSurf; - int oldSort; - float originalTime; - - // save original time for entity shader offsets - originalTime = backEnd.refdef.floatTime; - - // clear the z buffer, set the modelview, etc - RB_BeginDrawingView (); - - // draw everything - oldEntityNum = -1; - backEnd.currentEntity = &tr.worldEntity; - oldShader = NULL; - oldFogNum = -1; - oldDepthRange = qfalse; - wasCrosshair = qfalse; - oldDlighted = qfalse; - oldSort = -1; - depthRange = qfalse; - - backEnd.pc.c_surfaces += numDrawSurfs; - - for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { - if ( drawSurf->sort == oldSort ) { - // fast path, same as previous sort - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - continue; - } - oldSort = drawSurf->sort; - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); - - // - // change the tess parameters if needed - // a "entityMergable" shader is a shader that can have surfaces from seperate - // entities merged into a single batch, like smoke and blood puff sprites - if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted - || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { - if (oldShader != NULL) { - RB_EndSurface(); - } - RB_BeginSurface( shader, fogNum ); - oldShader = shader; - oldFogNum = fogNum; - oldDlighted = dlighted; - } - - // - // change the modelview matrix if needed - // - if ( entityNum != oldEntityNum ) { - depthRange = isCrosshair = qfalse; - - if ( entityNum != REFENTITYNUM_WORLD ) { - backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; - backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; - // we have to reset the shaderTime as well otherwise image animations start - // from the wrong frame - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - - // set up the transformation matrix - R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); - - // set up the dynamic lighting if needed - if ( backEnd.currentEntity->needDlights ) { - R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); - } - - if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) - { - // hack the depth range to prevent view model from poking into walls - depthRange = qtrue; - - if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) - isCrosshair = qtrue; - } - } else { - backEnd.currentEntity = &tr.worldEntity; - backEnd.refdef.floatTime = originalTime; - backEnd.or = backEnd.viewParms.world; - // we have to reset the shaderTime as well otherwise image animations on - // the world (like water) continue with the wrong frame - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); - } - - qglLoadMatrixf( backEnd.or.modelMatrix ); - - // - // change depthrange. Also change projection matrix so first person weapon does not look like coming - // out of the screen. - // - if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) - { - if (depthRange) - { - if(backEnd.viewParms.stereoFrame != STEREO_CENTER) - { - if(isCrosshair) - { - if(oldDepthRange) - { - // was not a crosshair but now is, change back proj matrix - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf(backEnd.viewParms.projectionMatrix); - qglMatrixMode(GL_MODELVIEW); - } - } - else - { - viewParms_t temp = backEnd.viewParms; - - R_SetupProjection(&temp, r_znear->value, qfalse); - - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf(temp.projectionMatrix); - qglMatrixMode(GL_MODELVIEW); - } - } - - if(!oldDepthRange) - qglDepthRange (0, 0.3); - } - else - { - if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) - { - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf(backEnd.viewParms.projectionMatrix); - qglMatrixMode(GL_MODELVIEW); - } - - qglDepthRange (0, 1); - } - - oldDepthRange = depthRange; - wasCrosshair = isCrosshair; - } - - oldEntityNum = entityNum; - } - - // add the triangles for this surface - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - } - - backEnd.refdef.floatTime = originalTime; - - // draw the contents of the last shader batch - if (oldShader != NULL) { - RB_EndSurface(); - } - - // go back to the world modelview matrix - qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); - if ( depthRange ) { - qglDepthRange (0, 1); - } - - if (r_drawSun->integer) { - RB_DrawSun(0.1, tr.sunShader); - } - - // darken down any stencil shadows - RB_ShadowFinish(); - - // add light flares on lights that aren't obscured - RB_RenderFlares(); -} - - -/* -============================================================================ - -RENDER BACK END FUNCTIONS - -============================================================================ -*/ - -/* -================ -RB_SetGL2D - -================ -*/ -void RB_SetGL2D (void) { - backEnd.projection2D = qtrue; - - // set 2D virtual screen size - qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - qglMatrixMode(GL_PROJECTION); - qglLoadIdentity (); - qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1); - qglMatrixMode(GL_MODELVIEW); - qglLoadIdentity (); - - GL_State( GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - - qglDisable( GL_CULL_FACE ); - qglDisable( GL_CLIP_PLANE0 ); - - // set time for 2D shaders - backEnd.refdef.time = ri.Milliseconds(); - backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f; -} - - -/* -============= -RE_StretchRaw - -FIXME: not exactly backend -Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. -Used for cinematics. -============= -*/ -void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { - int i, j; - int start, end; - - if ( !tr.registered ) { - return; - } - R_IssuePendingRenderCommands(); - - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - // we definately want to sync every frame for the cinematics - qglFinish(); - - start = 0; - if ( r_speeds->integer ) { - start = ri.Milliseconds(); - } - - // make sure rows and cols are powers of 2 - for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { - } - for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { - } - if ( ( 1 << i ) != cols || ( 1 << j ) != rows) { - ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); - } - - GL_Bind( tr.scratchImage[client] ); - - // if the scratchImage isn't in the format we want, specify it as a new texture - if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { - tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; - tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; - qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - } else { - if (dirty) { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression - qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); - } - } - - if ( r_speeds->integer ) { - end = ri.Milliseconds(); - ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); - } - - RB_SetGL2D(); - - qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); - - qglBegin (GL_QUADS); - qglTexCoord2f ( 0.5f / cols, 0.5f / rows ); - qglVertex2f (x, y); - qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows ); - qglVertex2f (x+w, y); - qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows ); - qglVertex2f (x+w, y+h); - qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows ); - qglVertex2f (x, y+h); - qglEnd (); -} - -void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { - - GL_Bind( tr.scratchImage[client] ); - - // if the scratchImage isn't in the format we want, specify it as a new texture - if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { - tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; - tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; - qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - } else { - if (dirty) { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression - qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); - } - } -} - - -/* -============= -RB_SetColor - -============= -*/ -const void *RB_SetColor( const void *data ) { - const setColorCommand_t *cmd; - - cmd = (const setColorCommand_t *)data; - - backEnd.color2D[0] = cmd->color[0] * 255; - backEnd.color2D[1] = cmd->color[1] * 255; - backEnd.color2D[2] = cmd->color[2] * 255; - backEnd.color2D[3] = cmd->color[3] * 255; - - return (const void *)(cmd + 1); -} - -/* -============= -RB_StretchPic -============= -*/ -const void *RB_StretchPic ( const void *data ) { - const stretchPicCommand_t *cmd; - shader_t *shader; - int numVerts, numIndexes; - - cmd = (const stretchPicCommand_t *)data; - - if ( !backEnd.projection2D ) { - RB_SetGL2D(); - } - - shader = cmd->shader; - if ( shader != tess.shader ) { - if ( tess.numIndexes ) { - RB_EndSurface(); - } - backEnd.currentEntity = &backEnd.entity2D; - RB_BeginSurface( shader, 0 ); - } - - RB_CHECKOVERFLOW( 4, 6 ); - numVerts = tess.numVertexes; - numIndexes = tess.numIndexes; - - tess.numVertexes += 4; - tess.numIndexes += 6; - - tess.indexes[ numIndexes ] = numVerts + 3; - tess.indexes[ numIndexes + 1 ] = numVerts + 0; - tess.indexes[ numIndexes + 2 ] = numVerts + 2; - tess.indexes[ numIndexes + 3 ] = numVerts + 2; - tess.indexes[ numIndexes + 4 ] = numVerts + 0; - tess.indexes[ numIndexes + 5 ] = numVerts + 1; - - *(int *)tess.vertexColors[ numVerts ] = - *(int *)tess.vertexColors[ numVerts + 1 ] = - *(int *)tess.vertexColors[ numVerts + 2 ] = - *(int *)tess.vertexColors[ numVerts + 3 ] = *(int *)backEnd.color2D; - - tess.xyz[ numVerts ][0] = cmd->x; - tess.xyz[ numVerts ][1] = cmd->y; - tess.xyz[ numVerts ][2] = 0; - - tess.texCoords[ numVerts ][0][0] = cmd->s1; - tess.texCoords[ numVerts ][0][1] = cmd->t1; - - tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w; - tess.xyz[ numVerts + 1 ][1] = cmd->y; - tess.xyz[ numVerts + 1 ][2] = 0; - - tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2; - tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1; - - tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w; - tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h; - tess.xyz[ numVerts + 2 ][2] = 0; - - tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2; - tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2; - - tess.xyz[ numVerts + 3 ][0] = cmd->x; - tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h; - tess.xyz[ numVerts + 3 ][2] = 0; - - tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1; - tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2; - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_DrawSurfs - -============= -*/ -const void *RB_DrawSurfs( const void *data ) { - const drawSurfsCommand_t *cmd; - - // finish any 2D drawing if needed - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - cmd = (const drawSurfsCommand_t *)data; - - backEnd.refdef = cmd->refdef; - backEnd.viewParms = cmd->viewParms; - - RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_DrawBuffer - -============= -*/ -const void *RB_DrawBuffer( const void *data ) { - const drawBufferCommand_t *cmd; - - cmd = (const drawBufferCommand_t *)data; - - qglDrawBuffer( cmd->buffer ); - - // clear screen for debugging - if ( r_clear->integer ) { - qglClearColor( 1, 0, 0.5, 1 ); - qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - } - - return (const void *)(cmd + 1); -} - -/* -=============== -RB_ShowImages - -Draw all the images to the screen, on top of whatever -was there. This is used to test for texture thrashing. - -Also called by RE_EndRegistration -=============== -*/ -void RB_ShowImages( void ) { - int i; - image_t *image; - float x, y, w, h; - int start, end; - - if ( !backEnd.projection2D ) { - RB_SetGL2D(); - } - - qglClear( GL_COLOR_BUFFER_BIT ); - - qglFinish(); - - start = ri.Milliseconds(); - - for ( i=0 ; iinteger == 2 ) { - w *= image->uploadWidth / 512.0f; - h *= image->uploadHeight / 512.0f; - } - - GL_Bind( image ); - qglBegin (GL_QUADS); - qglTexCoord2f( 0, 0 ); - qglVertex2f( x, y ); - qglTexCoord2f( 1, 0 ); - qglVertex2f( x + w, y ); - qglTexCoord2f( 1, 1 ); - qglVertex2f( x + w, y + h ); - qglTexCoord2f( 0, 1 ); - qglVertex2f( x, y + h ); - qglEnd(); - } - - qglFinish(); - - end = ri.Milliseconds(); - ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); - -} - -/* -============= -RB_ColorMask - -============= -*/ -const void *RB_ColorMask(const void *data) -{ - const colorMaskCommand_t *cmd = data; - - qglColorMask(cmd->rgba[0], cmd->rgba[1], cmd->rgba[2], cmd->rgba[3]); - - return (const void *)(cmd + 1); -} - -/* -============= -RB_ClearDepth - -============= -*/ -const void *RB_ClearDepth(const void *data) -{ - const clearDepthCommand_t *cmd = data; - - if(tess.numIndexes) - RB_EndSurface(); - - // texture swapping test - if (r_showImages->integer) - RB_ShowImages(); - - qglClear(GL_DEPTH_BUFFER_BIT); - - return (const void *)(cmd + 1); -} - -/* -============= -RB_SwapBuffers - -============= -*/ -const void *RB_SwapBuffers( const void *data ) { - const swapBuffersCommand_t *cmd; - - // finish any 2D drawing if needed - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - // texture swapping test - if ( r_showImages->integer ) { - RB_ShowImages(); - } - - cmd = (const swapBuffersCommand_t *)data; - - // we measure overdraw by reading back the stencil buffer and - // counting up the number of increments that have happened - if ( r_measureOverdraw->integer ) { - int i; - long sum = 0; - unsigned char *stencilReadback; - - stencilReadback = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight ); - qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); - - for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) { - sum += stencilReadback[i]; - } - - backEnd.pc.c_overDraw += sum; - ri.Hunk_FreeTempMemory( stencilReadback ); - } - - - if ( !glState.finishCalled ) { - qglFinish(); - } - - GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" ); - - GLimp_EndFrame(); - - backEnd.projection2D = qfalse; - - return (const void *)(cmd + 1); -} - -/* -==================== -RB_ExecuteRenderCommands -==================== -*/ -void RB_ExecuteRenderCommands( const void *data ) { - int t1, t2; - - t1 = ri.Milliseconds (); - - while ( 1 ) { - data = PADP(data, sizeof(void *)); - - switch ( *(const int *)data ) { - case RC_SET_COLOR: - data = RB_SetColor( data ); - break; - case RC_STRETCH_PIC: - data = RB_StretchPic( data ); - break; - case RC_DRAW_SURFS: - data = RB_DrawSurfs( data ); - break; - case RC_DRAW_BUFFER: - data = RB_DrawBuffer( data ); - break; - case RC_SWAP_BUFFERS: - data = RB_SwapBuffers( data ); - break; - case RC_SCREENSHOT: - data = RB_TakeScreenshotCmd( data ); - break; - case RC_VIDEOFRAME: - data = RB_TakeVideoFrameCmd( data ); - break; - case RC_COLORMASK: - data = RB_ColorMask(data); - break; - case RC_CLEARDEPTH: - data = RB_ClearDepth(data); - break; - case RC_END_OF_LIST: - default: - // stop rendering - t2 = ri.Milliseconds (); - backEnd.pc.msec = t2 - t1; - return; - } - } - -} diff --git a/code/renderergl1/tr_bsp.c b/code/renderergl1/tr_bsp.c deleted file mode 100644 index 7ca4d9776b..0000000000 --- a/code/renderergl1/tr_bsp.c +++ /dev/null @@ -1,1870 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_map.c - -#include "tr_local.h" - -/* - -Loads and prepares a map file for scene rendering. - -A single entry point: - -void RE_LoadWorldMap( const char *name ); - -*/ - -static world_t s_worldData; -static byte *fileBase; - -int c_subdivisions; -int c_gridVerts; - -//=============================================================================== - -static void HSVtoRGB( float h, float s, float v, float rgb[3] ) -{ - int i; - float f; - float p, q, t; - - h *= 5; - - i = floor( h ); - f = h - i; - - p = v * ( 1 - s ); - q = v * ( 1 - s * f ); - t = v * ( 1 - s * ( 1 - f ) ); - - switch ( i ) - { - case 0: - rgb[0] = v; - rgb[1] = t; - rgb[2] = p; - break; - case 1: - rgb[0] = q; - rgb[1] = v; - rgb[2] = p; - break; - case 2: - rgb[0] = p; - rgb[1] = v; - rgb[2] = t; - break; - case 3: - rgb[0] = p; - rgb[1] = q; - rgb[2] = v; - break; - case 4: - rgb[0] = t; - rgb[1] = p; - rgb[2] = v; - break; - case 5: - rgb[0] = v; - rgb[1] = p; - rgb[2] = q; - break; - } -} - -/* -=============== -R_ColorShiftLightingBytes - -=============== -*/ -static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { - int shift, r, g, b; - - // shift the color data based on overbright range - shift = r_mapOverBrightBits->integer - tr.overbrightBits; - - // shift the data based on overbright range - r = in[0] << shift; - g = in[1] << shift; - b = in[2] << shift; - - // normalize by color instead of saturating to white - if ( ( r | g | b ) > 255 ) { - int max; - - max = r > g ? r : g; - max = max > b ? max : b; - r = r * 255 / max; - g = g * 255 / max; - b = b * 255 / max; - } - - out[0] = r; - out[1] = g; - out[2] = b; - out[3] = in[3]; -} - -/* -=============== -R_LoadLightmaps - -=============== -*/ -#define LIGHTMAP_SIZE 128 -static void R_LoadLightmaps( lump_t *l ) { - byte *buf, *buf_p; - int len; - byte image[LIGHTMAP_SIZE*LIGHTMAP_SIZE*4]; - int i, j; - float maxIntensity = 0; - double sumIntensity = 0; - - len = l->filelen; - if ( !len ) { - return; - } - buf = fileBase + l->fileofs; - - // we are about to upload textures - R_IssuePendingRenderCommands(); - - // create all the lightmaps - tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3); - if ( tr.numLightmaps == 1 ) { - //FIXME: HACK: maps with only one lightmap turn up fullbright for some reason. - //this avoids this, but isn't the correct solution. - tr.numLightmaps++; - } - - // if we are in r_vertexLight mode, we don't need the lightmaps at all - if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - return; - } - - tr.lightmaps = ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low ); - for ( i = 0 ; i < tr.numLightmaps ; i++ ) { - // expand the 24 bit on-disk to 32 bit - buf_p = buf + i * LIGHTMAP_SIZE*LIGHTMAP_SIZE * 3; - - if ( r_lightmap->integer == 2 ) - { // color code by intensity as development tool (FIXME: check range) - for ( j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) - { - float r = buf_p[j*3+0]; - float g = buf_p[j*3+1]; - float b = buf_p[j*3+2]; - float intensity; - float out[3] = {0.0, 0.0, 0.0}; - - intensity = 0.33f * r + 0.685f * g + 0.063f * b; - - if ( intensity > 255 ) - intensity = 1.0f; - else - intensity /= 255.0f; - - if ( intensity > maxIntensity ) - maxIntensity = intensity; - - HSVtoRGB( intensity, 1.00, 0.50, out ); - - image[j*4+0] = out[0] * 255; - image[j*4+1] = out[1] * 255; - image[j*4+2] = out[2] * 255; - image[j*4+3] = 255; - - sumIntensity += intensity; - } - } else { - for ( j = 0 ; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) { - R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] ); - image[j*4+3] = 255; - } - } - tr.lightmaps[i] = R_CreateImage( va("*lightmap%d",i), image, - LIGHTMAP_SIZE, LIGHTMAP_SIZE, IMGTYPE_COLORALPHA, - IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, 0 ); - } - - if ( r_lightmap->integer == 2 ) { - ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) ); - } -} - - -/* -================= -RE_SetWorldVisData - -This is called by the clipmodel subsystem so we can share the 1.8 megs of -space in big maps... -================= -*/ -void RE_SetWorldVisData( const byte *vis ) { - tr.externalVisData = vis; -} - - -/* -================= -R_LoadVisibility -================= -*/ -static void R_LoadVisibility( lump_t *l ) { - int len; - byte *buf; - - len = ( s_worldData.numClusters + 63 ) & ~63; - s_worldData.novis = ri.Hunk_Alloc( len, h_low ); - Com_Memset( s_worldData.novis, 0xff, len ); - - len = l->filelen; - if ( !len ) { - return; - } - buf = fileBase + l->fileofs; - - s_worldData.numClusters = LittleLong( ((int *)buf)[0] ); - s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] ); - - // CM_Load should have given us the vis data to share, so - // we don't need to allocate another copy - if ( tr.externalVisData ) { - s_worldData.vis = tr.externalVisData; - } else { - byte *dest; - - dest = ri.Hunk_Alloc( len - 8, h_low ); - Com_Memcpy( dest, buf + 8, len - 8 ); - s_worldData.vis = dest; - } -} - -//=============================================================================== - - -/* -=============== -ShaderForShaderNum -=============== -*/ -static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) { - shader_t *shader; - dshader_t *dsh; - - int _shaderNum = LittleLong( shaderNum ); - if ( _shaderNum < 0 || _shaderNum >= s_worldData.numShaders ) { - ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", _shaderNum ); - } - dsh = &s_worldData.shaders[ _shaderNum ]; - - if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - lightmapNum = LIGHTMAP_BY_VERTEX; - } - - if ( r_fullbright->integer ) { - lightmapNum = LIGHTMAP_WHITEIMAGE; - } - - shader = R_FindShader( dsh->shader, lightmapNum, qtrue ); - - // if the shader had errors, just use default shader - if ( shader->defaultShader ) { - return tr.defaultShader; - } - - return shader; -} - -/* -=============== -ParseFace -=============== -*/ -static void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { - int i, j; - srfSurfaceFace_t *cv; - int numPoints, numIndexes; - int lightmapNum; - int sfaceSize, ofsIndexes; - - lightmapNum = LittleLong( ds->lightmapNum ); - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - numPoints = LittleLong( ds->numVerts ); - if (numPoints > MAX_FACE_POINTS) { - ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numPoints); - numPoints = MAX_FACE_POINTS; - surf->shader = tr.defaultShader; - } - - numIndexes = LittleLong( ds->numIndexes ); - - // create the srfSurfaceFace_t - sfaceSize = ( size_t ) &((srfSurfaceFace_t *)0)->points[numPoints]; - ofsIndexes = sfaceSize; - sfaceSize += sizeof( int ) * numIndexes; - - cv = ri.Hunk_Alloc( sfaceSize, h_low ); - cv->surfaceType = SF_FACE; - cv->numPoints = numPoints; - cv->numIndices = numIndexes; - cv->ofsIndices = ofsIndexes; - - verts += LittleLong( ds->firstVert ); - for ( i = 0 ; i < numPoints ; i++ ) { - for ( j = 0 ; j < 3 ; j++ ) { - cv->points[i][j] = LittleFloat( verts[i].xyz[j] ); - } - for ( j = 0 ; j < 2 ; j++ ) { - cv->points[i][3+j] = LittleFloat( verts[i].st[j] ); - cv->points[i][5+j] = LittleFloat( verts[i].lightmap[j] ); - } - R_ColorShiftLightingBytes( verts[i].color, (byte *)&cv->points[i][7] ); - } - - indexes += LittleLong( ds->firstIndex ); - for ( i = 0 ; i < numIndexes ; i++ ) { - ((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] ); - } - - // take the plane information from the lightmap vector - for ( i = 0 ; i < 3 ; i++ ) { - cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); - } - cv->plane.dist = DotProduct( cv->points[0], cv->plane.normal ); - SetPlaneSignbits( &cv->plane ); - cv->plane.type = PlaneTypeForNormal( cv->plane.normal ); - - surf->data = (surfaceType_t *)cv; -} - - -/* -=============== -ParseMesh -=============== -*/ -static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) { - srfGridMesh_t *grid; - int i, j; - int width, height, numPoints; - drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]; - int lightmapNum; - vec3_t bounds[2]; - vec3_t tmpVec; - static surfaceType_t skipData = SF_SKIP; - - lightmapNum = LittleLong( ds->lightmapNum ); - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - // we may have a nodraw surface, because they might still need to - // be around for movement clipping - if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) { - surf->data = &skipData; - return; - } - - width = LittleLong( ds->patchWidth ); - height = LittleLong( ds->patchHeight ); - - verts += LittleLong( ds->firstVert ); - numPoints = width * height; - for ( i = 0 ; i < numPoints ; i++ ) { - for ( j = 0 ; j < 3 ; j++ ) { - points[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); - points[i].normal[j] = LittleFloat( verts[i].normal[j] ); - } - for ( j = 0 ; j < 2 ; j++ ) { - points[i].st[j] = LittleFloat( verts[i].st[j] ); - points[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] ); - } - R_ColorShiftLightingBytes( verts[i].color, points[i].color ); - } - - // pre-tesseleate - grid = R_SubdividePatchToGrid( width, height, points ); - surf->data = (surfaceType_t *)grid; - - // copy the level of detail origin, which is the center - // of the group of all curves that must subdivide the same - // to avoid cracking - for ( i = 0 ; i < 3 ; i++ ) { - bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] ); - bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] ); - } - VectorAdd( bounds[0], bounds[1], bounds[1] ); - VectorScale( bounds[1], 0.5f, grid->lodOrigin ); - VectorSubtract( bounds[0], grid->lodOrigin, tmpVec ); - grid->lodRadius = VectorLength( tmpVec ); -} - -/* -=============== -ParseTriSurf -=============== -*/ -static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { - srfTriangles_t *tri; - int i, j; - int numVerts, numIndexes; - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - numVerts = LittleLong( ds->numVerts ); - numIndexes = LittleLong( ds->numIndexes ); - - tri = ri.Hunk_Alloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] ) - + numIndexes * sizeof( tri->indexes[0] ), h_low ); - tri->surfaceType = SF_TRIANGLES; - tri->numVerts = numVerts; - tri->numIndexes = numIndexes; - tri->verts = (drawVert_t *)(tri + 1); - tri->indexes = (int *)(tri->verts + tri->numVerts ); - - surf->data = (surfaceType_t *)tri; - - // copy vertexes - ClearBounds( tri->bounds[0], tri->bounds[1] ); - verts += LittleLong( ds->firstVert ); - for ( i = 0 ; i < numVerts ; i++ ) { - for ( j = 0 ; j < 3 ; j++ ) { - tri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); - tri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] ); - } - AddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] ); - for ( j = 0 ; j < 2 ; j++ ) { - tri->verts[i].st[j] = LittleFloat( verts[i].st[j] ); - tri->verts[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] ); - } - - R_ColorShiftLightingBytes( verts[i].color, tri->verts[i].color ); - } - - // copy indexes - indexes += LittleLong( ds->firstIndex ); - for ( i = 0 ; i < numIndexes ; i++ ) { - tri->indexes[i] = LittleLong( indexes[i] ); - if ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) { - ri.Error( ERR_DROP, "Bad index in triangle surface" ); - } - } -} - -/* -=============== -ParseFlare -=============== -*/ -static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { - srfFlare_t *flare; - int i; - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - flare = ri.Hunk_Alloc( sizeof( *flare ), h_low ); - flare->surfaceType = SF_FLARE; - - surf->data = (surfaceType_t *)flare; - - for ( i = 0 ; i < 3 ; i++ ) { - flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] ); - flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] ); - flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); - } -} - - -/* -================= -R_MergedWidthPoints - -returns true if there are grid points merged on a width edge -================= -*/ -int R_MergedWidthPoints(srfGridMesh_t *grid, int offset) { - int i, j; - - for (i = 1; i < grid->width-1; i++) { - for (j = i + 1; j < grid->width-1; j++) { - if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue; - if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue; - if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue; - return qtrue; - } - } - return qfalse; -} - -/* -================= -R_MergedHeightPoints - -returns true if there are grid points merged on a height edge -================= -*/ -int R_MergedHeightPoints(srfGridMesh_t *grid, int offset) { - int i, j; - - for (i = 1; i < grid->height-1; i++) { - for (j = i + 1; j < grid->height-1; j++) { - if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue; - if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue; - if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue; - return qtrue; - } - } - return qfalse; -} - -/* -================= -R_FixSharedVertexLodError_r - -NOTE: never sync LoD through grid edges with merged points! - -FIXME: write generalized version that also avoids cracks between a patch and one that meets half way? -================= -*/ -void R_FixSharedVertexLodError_r( int start, srfGridMesh_t *grid1 ) { - int j, k, l, m, n, offset1, offset2, touch; - srfGridMesh_t *grid2; - - for ( j = start; j < s_worldData.numsurfaces; j++ ) { - // - grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; - // if this surface is not a grid - if ( grid2->surfaceType != SF_GRID ) continue; - // if the LOD errors are already fixed for this patch - if ( grid2->lodFixed == 2 ) continue; - // grids in the same LOD group should have the exact same lod radius - if ( grid1->lodRadius != grid2->lodRadius ) continue; - // grids in the same LOD group should have the exact same lod origin - if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; - if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; - if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; - // - touch = qfalse; - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) continue; - for (k = 1; k < grid1->width-1; k++) { - for (m = 0; m < 2; m++) { - - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - if (R_MergedWidthPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->width-1; l++) { - // - if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->widthLodError[l] = grid1->widthLodError[k]; - touch = qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (m) offset2 = grid2->width-1; - else offset2 = 0; - if (R_MergedHeightPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->height-1; l++) { - // - if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->heightLodError[l] = grid1->widthLodError[k]; - touch = qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) continue; - for (k = 1; k < grid1->height-1; k++) { - for (m = 0; m < 2; m++) { - - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - if (R_MergedWidthPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->width-1; l++) { - // - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->widthLodError[l] = grid1->heightLodError[k]; - touch = qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (m) offset2 = grid2->width-1; - else offset2 = 0; - if (R_MergedHeightPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->height-1; l++) { - // - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->heightLodError[l] = grid1->heightLodError[k]; - touch = qtrue; - } - } - } - } - if (touch) { - grid2->lodFixed = 2; - R_FixSharedVertexLodError_r ( start, grid2 ); - //NOTE: this would be correct but makes things really slow - //grid2->lodFixed = 1; - } - } -} - -/* -================= -R_FixSharedVertexLodError - -This function assumes that all patches in one group are nicely stitched together for the highest LoD. -If this is not the case this function will still do its job but won't fix the highest LoD cracks. -================= -*/ -void R_FixSharedVertexLodError( void ) { - int i; - srfGridMesh_t *grid1; - - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid1->surfaceType != SF_GRID ) - continue; - // - if ( grid1->lodFixed ) - continue; - // - grid1->lodFixed = 2; - // recursively fix other patches in the same LOD group - R_FixSharedVertexLodError_r( i + 1, grid1); - } -} - - -/* -=============== -R_StitchPatches -=============== -*/ -int R_StitchPatches( int grid1num, int grid2num ) { - float *v1, *v2; - srfGridMesh_t *grid1, *grid2; - int k, l, m, n, offset1, offset2, row, column; - - grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; - grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data; - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) - continue; - for (k = 0; k < grid1->width-2; k += 2) { - - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k + 2 + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k + 2 + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) - continue; - for (k = 0; k < grid1->height-2; k += 2) { - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) - continue; - for (k = grid1->width-1; k > 1; k -= 2) { - - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k - 2 + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k - 2 + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); - if (!grid2) - break; - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) - continue; - for (k = grid1->height-1; k > 1; k -= 2) { - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - return qfalse; -} - -/* -=============== -R_TryStitchPatch - -This function will try to stitch patches in the same LoD group together for the highest LoD. - -Only single missing vertice cracks will be fixed. - -Vertices will be joined at the patch side a crack is first found, at the other side -of the patch (on the same row or column) the vertices will not be joined and cracks -might still appear at that side. -=============== -*/ -int R_TryStitchingPatch( int grid1num ) { - int j, numstitches; - srfGridMesh_t *grid1, *grid2; - - numstitches = 0; - grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; - for ( j = 0; j < s_worldData.numsurfaces; j++ ) { - // - grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; - // if this surface is not a grid - if ( grid2->surfaceType != SF_GRID ) continue; - // grids in the same LOD group should have the exact same lod radius - if ( grid1->lodRadius != grid2->lodRadius ) continue; - // grids in the same LOD group should have the exact same lod origin - if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; - if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; - if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; - // - while (R_StitchPatches(grid1num, j)) - { - numstitches++; - } - } - return numstitches; -} - -/* -=============== -R_StitchAllPatches -=============== -*/ -void R_StitchAllPatches( void ) { - int i, stitched, numstitches; - srfGridMesh_t *grid1; - - numstitches = 0; - do - { - stitched = qfalse; - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid1->surfaceType != SF_GRID ) - continue; - // - if ( grid1->lodStitched ) - continue; - // - grid1->lodStitched = qtrue; - stitched = qtrue; - // - numstitches += R_TryStitchingPatch( i ); - } - } - while (stitched); - ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches ); -} - -/* -=============== -R_MovePatchSurfacesToHunk -=============== -*/ -void R_MovePatchSurfacesToHunk(void) { - int i, size; - srfGridMesh_t *grid, *hunkgrid; - - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid = (srfGridMesh_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid->surfaceType != SF_GRID ) - continue; - // - size = (grid->width * grid->height - 1) * sizeof( drawVert_t ) + sizeof( *grid ); - hunkgrid = ri.Hunk_Alloc( size, h_low ); - Com_Memcpy(hunkgrid, grid, size); - - hunkgrid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_low ); - Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 ); - - hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_low ); - Com_Memcpy( hunkgrid->heightLodError, grid->heightLodError, grid->height * 4 ); - - R_FreeSurfaceGridMesh( grid ); - - s_worldData.surfaces[i].data = (void *) hunkgrid; - } -} - -/* -=============== -R_LoadSurfaces -=============== -*/ -static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { - dsurface_t *in; - msurface_t *out; - drawVert_t *dv; - int *indexes; - int count; - int numFaces, numMeshes, numTriSurfs, numFlares; - int i; - - numFaces = 0; - numMeshes = 0; - numTriSurfs = 0; - numFlares = 0; - - in = (void *)(fileBase + surfs->fileofs); - if (surfs->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = surfs->filelen / sizeof(*in); - - dv = (void *)(fileBase + verts->fileofs); - if (verts->filelen % sizeof(*dv)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - - indexes = (void *)(fileBase + indexLump->fileofs); - if ( indexLump->filelen % sizeof(*indexes)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - - out = ri.Hunk_Alloc ( count * sizeof(*out), h_low ); - - s_worldData.surfaces = out; - s_worldData.numsurfaces = count; - - for ( i = 0 ; i < count ; i++, in++, out++ ) { - switch ( LittleLong( in->surfaceType ) ) { - case MST_PATCH: - ParseMesh ( in, dv, out ); - numMeshes++; - break; - case MST_TRIANGLE_SOUP: - ParseTriSurf( in, dv, out, indexes ); - numTriSurfs++; - break; - case MST_PLANAR: - ParseFace( in, dv, out, indexes ); - numFaces++; - break; - case MST_FLARE: - ParseFlare( in, dv, out, indexes ); - numFlares++; - break; - default: - ri.Error( ERR_DROP, "Bad surfaceType" ); - } - } - -#ifdef PATCH_STITCHING - R_StitchAllPatches(); -#endif - - R_FixSharedVertexLodError(); - -#ifdef PATCH_STITCHING - R_MovePatchSurfacesToHunk(); -#endif - - ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", - numFaces, numMeshes, numTriSurfs, numFlares ); -} - - - -/* -================= -R_LoadSubmodels -================= -*/ -static void R_LoadSubmodels( lump_t *l ) { - dmodel_t *in; - bmodel_t *out; - int i, j, count; - - in = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - - s_worldData.bmodels = out = ri.Hunk_Alloc( count * sizeof(*out), h_low ); - - for ( i=0 ; itype = MOD_BRUSH; - model->bmodel = out; - Com_sprintf( model->name, sizeof( model->name ), "*%d", i ); - - for (j=0 ; j<3 ; j++) { - out->bounds[0][j] = LittleFloat (in->mins[j]); - out->bounds[1][j] = LittleFloat (in->maxs[j]); - } - - out->firstSurface = s_worldData.surfaces + LittleLong( in->firstSurface ); - out->numSurfaces = LittleLong( in->numSurfaces ); - } -} - - - -//================================================================== - -/* -================= -R_SetParent -================= -*/ -static void R_SetParent (mnode_t *node, mnode_t *parent) -{ - node->parent = parent; - if (node->contents != -1) - return; - R_SetParent (node->children[0], node); - R_SetParent (node->children[1], node); -} - -/* -================= -R_LoadNodesAndLeafs -================= -*/ -static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) { - int i, j, p; - dnode_t *in; - dleaf_t *inLeaf; - mnode_t *out; - int numNodes, numLeafs; - - in = (void *)(fileBase + nodeLump->fileofs); - if (nodeLump->filelen % sizeof(dnode_t) || - leafLump->filelen % sizeof(dleaf_t) ) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - numNodes = nodeLump->filelen / sizeof(dnode_t); - numLeafs = leafLump->filelen / sizeof(dleaf_t); - - out = ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low); - - s_worldData.nodes = out; - s_worldData.numnodes = numNodes + numLeafs; - s_worldData.numDecisionNodes = numNodes; - - // load nodes - for ( i=0 ; imins[j] = LittleLong (in->mins[j]); - out->maxs[j] = LittleLong (in->maxs[j]); - } - - p = LittleLong(in->planeNum); - out->plane = s_worldData.planes + p; - - out->contents = CONTENTS_NODE; // differentiate from leafs - - for (j=0 ; j<2 ; j++) - { - p = LittleLong (in->children[j]); - if (p >= 0) - out->children[j] = s_worldData.nodes + p; - else - out->children[j] = s_worldData.nodes + numNodes + (-1 - p); - } - } - - // load leafs - inLeaf = (void *)(fileBase + leafLump->fileofs); - for ( i=0 ; imins[j] = LittleLong (inLeaf->mins[j]); - out->maxs[j] = LittleLong (inLeaf->maxs[j]); - } - - out->cluster = LittleLong(inLeaf->cluster); - out->area = LittleLong(inLeaf->area); - - if ( out->cluster >= s_worldData.numClusters ) { - s_worldData.numClusters = out->cluster + 1; - } - - out->firstmarksurface = s_worldData.marksurfaces + - LittleLong(inLeaf->firstLeafSurface); - out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces); - } - - // chain decendants - R_SetParent (s_worldData.nodes, NULL); -} - -//============================================================================= - -/* -================= -R_LoadShaders -================= -*/ -static void R_LoadShaders( lump_t *l ) { - int i, count; - dshader_t *in, *out; - - in = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*sizeof(*out), h_low ); - - s_worldData.shaders = out; - s_worldData.numShaders = count; - - Com_Memcpy( out, in, count*sizeof(*out) ); - - for ( i=0 ; ifileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*sizeof(*out), h_low); - - s_worldData.marksurfaces = out; - s_worldData.nummarksurfaces = count; - - for ( i=0 ; ifileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*2*sizeof(*out), h_low); - - s_worldData.planes = out; - s_worldData.numplanes = count; - - for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); - if (out->normal[j] < 0) { - bits |= 1<dist = LittleFloat (in->dist); - out->type = PlaneTypeForNormal( out->normal ); - out->signbits = bits; - } -} - -/* -================= -R_LoadFogs - -================= -*/ -static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) { - int i; - fog_t *out; - dfog_t *fogs; - dbrush_t *brushes, *brush; - dbrushside_t *sides; - int count, brushesCount, sidesCount; - int sideNum; - int planeNum; - shader_t *shader; - float d; - int firstSide; - - fogs = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*fogs)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - count = l->filelen / sizeof(*fogs); - - // create fog strucutres for them - s_worldData.numfogs = count + 1; - s_worldData.fogs = ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low); - out = s_worldData.fogs + 1; - - if ( !count ) { - return; - } - - brushes = (void *)(fileBase + brushesLump->fileofs); - if (brushesLump->filelen % sizeof(*brushes)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - brushesCount = brushesLump->filelen / sizeof(*brushes); - - sides = (void *)(fileBase + sidesLump->fileofs); - if (sidesLump->filelen % sizeof(*sides)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - sidesCount = sidesLump->filelen / sizeof(*sides); - - for ( i=0 ; ioriginalBrushNumber = LittleLong( fogs->brushNum ); - - if ( (unsigned)out->originalBrushNumber >= brushesCount ) { - ri.Error( ERR_DROP, "fog brushNumber out of range" ); - } - brush = brushes + out->originalBrushNumber; - - firstSide = LittleLong( brush->firstSide ); - - if ( (unsigned)firstSide > sidesCount - 6 ) { - ri.Error( ERR_DROP, "fog brush sideNumber out of range" ); - } - - // brushes are always sorted with the axial sides first - sideNum = firstSide + 0; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 1; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][0] = s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 2; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 3; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][1] = s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 4; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 5; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][2] = s_worldData.planes[ planeNum ].dist; - - // get information from the shader for fog parameters - shader = R_FindShader( fogs->shader, LIGHTMAP_NONE, qtrue ); - - out->parms = shader->fogParms; - - out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight, - shader->fogParms.color[1] * tr.identityLight, - shader->fogParms.color[2] * tr.identityLight, 1.0 ); - - d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque; - out->tcScale = 1.0f / ( d * 8 ); - - // set the gradient vector - sideNum = LittleLong( fogs->visibleSide ); - - if ( sideNum == -1 ) { - out->hasSurface = qfalse; - } else { - out->hasSurface = qtrue; - planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum ); - VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface ); - out->surface[3] = -s_worldData.planes[ planeNum ].dist; - } - - out++; - } - -} - - -/* -================ -R_LoadLightGrid - -================ -*/ -void R_LoadLightGrid( lump_t *l ) { - int i; - vec3_t maxs; - int numGridPoints; - world_t *w; - float *wMins, *wMaxs; - - w = &s_worldData; - - w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0]; - w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1]; - w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2]; - - wMins = w->bmodels[0].bounds[0]; - wMaxs = w->bmodels[0].bounds[1]; - - for ( i = 0 ; i < 3 ; i++ ) { - w->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] ); - maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] ); - w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1; - } - - numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2]; - - if ( l->filelen != numGridPoints * 8 ) { - ri.Printf( PRINT_WARNING, "WARNING: light grid mismatch\n" ); - w->lightGridData = NULL; - return; - } - - w->lightGridData = ri.Hunk_Alloc( l->filelen, h_low ); - Com_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen ); - - // deal with overbright bits - for ( i = 0 ; i < numGridPoints ; i++ ) { - R_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] ); - R_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] ); - } -} - -/* -================ -R_LoadEntities -================ -*/ -void R_LoadEntities( lump_t *l ) { - char *p, *token, *s; - char keyname[MAX_TOKEN_CHARS]; - char value[MAX_TOKEN_CHARS]; - world_t *w; - - w = &s_worldData; - w->lightGridSize[0] = 64; - w->lightGridSize[1] = 64; - w->lightGridSize[2] = 128; - - p = (char *)(fileBase + l->fileofs); - - // store for reference by the cgame - w->entityString = ri.Hunk_Alloc( l->filelen + 1, h_low ); - strcpy( w->entityString, p ); - w->entityParsePoint = w->entityString; - - token = COM_ParseExt( &p, qtrue ); - if (!*token || *token != '{') { - return; - } - - // only parse the world spawn - while ( 1 ) { - // parse key - token = COM_ParseExt( &p, qtrue ); - - if ( !*token || *token == '}' ) { - break; - } - Q_strncpyz(keyname, token, sizeof(keyname)); - - // parse value - token = COM_ParseExt( &p, qtrue ); - - if ( !*token || *token == '}' ) { - break; - } - Q_strncpyz(value, token, sizeof(value)); - - // check for remapping of shaders for vertex lighting - s = "vertexremapshader"; - if (!Q_strncmp(keyname, s, strlen(s)) ) { - s = strchr(value, ';'); - if (!s) { - ri.Printf( PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value ); - break; - } - *s++ = 0; - if (r_vertexLight->integer) { - R_RemapShader(value, s, "0"); - } - continue; - } - // check for remapping of shaders - s = "remapshader"; - if (!Q_strncmp(keyname, s, strlen(s)) ) { - s = strchr(value, ';'); - if (!s) { - ri.Printf( PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value ); - break; - } - *s++ = 0; - R_RemapShader(value, s, "0"); - continue; - } - // check for a different grid size - if (!Q_stricmp(keyname, "gridsize")) { - sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] ); - continue; - } - } -} - -/* -================= -R_GetEntityToken -================= -*/ -qboolean R_GetEntityToken( char *buffer, int size ) { - const char *s; - - s = COM_Parse( &s_worldData.entityParsePoint ); - Q_strncpyz( buffer, s, size ); - if ( !s_worldData.entityParsePoint || !s[0] ) { - s_worldData.entityParsePoint = s_worldData.entityString; - return qfalse; - } else { - return qtrue; - } -} - -/* -================= -RE_LoadWorldMap - -Called directly from cgame -================= -*/ -void RE_LoadWorldMap( const char *name ) { - int i; - dheader_t *header; - union { - byte *b; - void *v; - } buffer; - byte *startMarker; - - if ( tr.worldMapLoaded ) { - ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map" ); - } - - // set default sun direction to be used if it isn't - // overridden by a shader - tr.sunDirection[0] = 0.45f; - tr.sunDirection[1] = 0.3f; - tr.sunDirection[2] = 0.9f; - - VectorNormalize( tr.sunDirection ); - - tr.worldMapLoaded = qtrue; - - // load it - ri.FS_ReadFile( name, &buffer.v ); - if ( !buffer.b ) { - ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name); - } - - // clear tr.world so if the level fails to load, the next - // try will not look at the partially loaded version - tr.world = NULL; - - Com_Memset( &s_worldData, 0, sizeof( s_worldData ) ); - Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) ); - - Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) ); - COM_StripExtension(s_worldData.baseName, s_worldData.baseName, sizeof(s_worldData.baseName)); - - startMarker = ri.Hunk_Alloc(0, h_low); - c_gridVerts = 0; - - header = (dheader_t *)buffer.b; - fileBase = (byte *)header; - - i = LittleLong (header->version); - if ( i != BSP_VERSION ) { - ri.Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)", - name, i, BSP_VERSION); - } - - // swap all the lumps - for (i=0 ; ilumps[LUMP_SHADERS] ); - R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS] ); - R_LoadPlanes (&header->lumps[LUMP_PLANES]); - R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] ); - R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] ); - R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]); - R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]); - R_LoadSubmodels (&header->lumps[LUMP_MODELS]); - R_LoadVisibility( &header->lumps[LUMP_VISIBILITY] ); - R_LoadEntities( &header->lumps[LUMP_ENTITIES] ); - R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] ); - - s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker; - - // only set tr.world now that we know the entire level has loaded properly - tr.world = &s_worldData; - - ri.FS_FreeFile( buffer.v ); -} - diff --git a/code/renderergl1/tr_cmds.c b/code/renderergl1/tr_cmds.c deleted file mode 100644 index 00b819acd8..0000000000 --- a/code/renderergl1/tr_cmds.c +++ /dev/null @@ -1,503 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -/* -===================== -R_PerformanceCounters -===================== -*/ -void R_PerformanceCounters( void ) { - if ( !r_speeds->integer ) { - // clear the counters even if we aren't printing - Com_Memset( &tr.pc, 0, sizeof( tr.pc ) ); - Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); - return; - } - - if (r_speeds->integer == 1) { - ri.Printf (PRINT_ALL, "%i/%i shaders/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n", - backEnd.pc.c_shaders, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes, - backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3, - R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) ); - } else if (r_speeds->integer == 2) { - ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", - tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out, - tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out ); - ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", - tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out, - tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out ); - } else if (r_speeds->integer == 3) { - ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster ); - } else if (r_speeds->integer == 4) { - if ( backEnd.pc.c_dlightVertexes ) { - ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n", - tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled, - backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 ); - } - } - else if (r_speeds->integer == 5 ) - { - ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar ); - } - else if (r_speeds->integer == 6 ) - { - ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n", - backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders ); - } - - Com_Memset( &tr.pc, 0, sizeof( tr.pc ) ); - Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); -} - - -/* -==================== -R_IssueRenderCommands -==================== -*/ -void R_IssueRenderCommands( qboolean runPerformanceCounters ) { - renderCommandList_t *cmdList; - - cmdList = &backEndData->commands; - assert(cmdList); - // add an end-of-list command - *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST; - - // clear it out, in case this is a sync and not a buffer flip - cmdList->used = 0; - - if ( runPerformanceCounters ) { - R_PerformanceCounters(); - } - - // actually start the commands going - if ( !r_skipBackEnd->integer ) { - // let it start on the new batch - RB_ExecuteRenderCommands( cmdList->cmds ); - } -} - - -/* -==================== -R_IssuePendingRenderCommands - -Issue any pending commands and wait for them to complete. -==================== -*/ -void R_IssuePendingRenderCommands( void ) { - if ( !tr.registered ) { - return; - } - R_IssueRenderCommands( qfalse ); -} - -/* -============ -R_GetCommandBuffer - -make sure there is enough command space -============ -*/ -void *R_GetCommandBuffer( int bytes ) { - renderCommandList_t *cmdList; - - cmdList = &backEndData->commands; - bytes = PAD(bytes, sizeof(void *)); - - // always leave room for the end of list command - if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) { - if ( bytes > MAX_RENDER_COMMANDS - 4 ) { - ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes ); - } - // if we run out of room, just start dropping commands - return NULL; - } - - cmdList->used += bytes; - - return cmdList->cmds + cmdList->used - bytes; -} - - -/* -============= -R_AddDrawSurfCmd - -============= -*/ -void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) { - drawSurfsCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_DRAW_SURFS; - - cmd->drawSurfs = drawSurfs; - cmd->numDrawSurfs = numDrawSurfs; - - cmd->refdef = tr.refdef; - cmd->viewParms = tr.viewParms; -} - - -/* -============= -RE_SetColor - -Passing NULL will set the color to white -============= -*/ -void RE_SetColor( const float *rgba ) { - setColorCommand_t *cmd; - - if ( !tr.registered ) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SET_COLOR; - if ( !rgba ) { - static float colorWhite[4] = { 1, 1, 1, 1 }; - - rgba = colorWhite; - } - - cmd->color[0] = rgba[0]; - cmd->color[1] = rgba[1]; - cmd->color[2] = rgba[2]; - cmd->color[3] = rgba[3]; -} - - -/* -============= -RE_StretchPic -============= -*/ -void RE_StretchPic ( float x, float y, float w, float h, - float s1, float t1, float s2, float t2, qhandle_t hShader ) { - stretchPicCommand_t *cmd; - - if (!tr.registered) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_STRETCH_PIC; - cmd->shader = R_GetShaderByHandle( hShader ); - cmd->x = x; - cmd->y = y; - cmd->w = w; - cmd->h = h; - cmd->s1 = s1; - cmd->t1 = t1; - cmd->s2 = s2; - cmd->t2 = t2; -} - -#define MODE_RED_CYAN 1 -#define MODE_RED_BLUE 2 -#define MODE_RED_GREEN 3 -#define MODE_GREEN_MAGENTA 4 -#define MODE_MAX MODE_GREEN_MAGENTA - -void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode) -{ - rgba[0] = rgba[1] = rgba[2] = rgba[3] = GL_TRUE; - - if(colormode > MODE_MAX) - { - if(stereoFrame == STEREO_LEFT) - stereoFrame = STEREO_RIGHT; - else if(stereoFrame == STEREO_RIGHT) - stereoFrame = STEREO_LEFT; - - colormode -= MODE_MAX; - } - - if(colormode == MODE_GREEN_MAGENTA) - { - if(stereoFrame == STEREO_LEFT) - rgba[0] = rgba[2] = GL_FALSE; - else if(stereoFrame == STEREO_RIGHT) - rgba[1] = GL_FALSE; - } - else - { - if(stereoFrame == STEREO_LEFT) - rgba[1] = rgba[2] = GL_FALSE; - else if(stereoFrame == STEREO_RIGHT) - { - rgba[0] = GL_FALSE; - - if(colormode == MODE_RED_BLUE) - rgba[1] = GL_FALSE; - else if(colormode == MODE_RED_GREEN) - rgba[2] = GL_FALSE; - } - } -} - - -/* -==================== -RE_BeginFrame - -If running in stereo, RE_BeginFrame will be called twice -for each RE_EndFrame -==================== -*/ -void RE_BeginFrame( stereoFrame_t stereoFrame ) { - drawBufferCommand_t *cmd = NULL; - colorMaskCommand_t *colcmd = NULL; - - if ( !tr.registered ) { - return; - } - glState.finishCalled = qfalse; - - tr.frameCount++; - tr.frameSceneNum = 0; - - // - // do overdraw measurement - // - if ( r_measureOverdraw->integer ) - { - if ( glConfig.stencilBits < 4 ) - { - ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits ); - ri.Cvar_Set( "r_measureOverdraw", "0" ); - r_measureOverdraw->modified = qfalse; - } - else if ( r_shadows->integer == 2 ) - { - ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" ); - ri.Cvar_Set( "r_measureOverdraw", "0" ); - r_measureOverdraw->modified = qfalse; - } - else - { - R_IssuePendingRenderCommands(); - qglEnable( GL_STENCIL_TEST ); - qglStencilMask( ~0U ); - qglClearStencil( 0U ); - qglStencilFunc( GL_ALWAYS, 0U, ~0U ); - qglStencilOp( GL_KEEP, GL_INCR, GL_INCR ); - } - r_measureOverdraw->modified = qfalse; - } - else - { - // this is only reached if it was on and is now off - if ( r_measureOverdraw->modified ) { - R_IssuePendingRenderCommands(); - qglDisable( GL_STENCIL_TEST ); - } - r_measureOverdraw->modified = qfalse; - } - - // - // texturemode stuff - // - if ( r_textureMode->modified ) { - R_IssuePendingRenderCommands(); - GL_TextureMode( r_textureMode->string ); - r_textureMode->modified = qfalse; - } - - // - // gamma stuff - // - if ( r_gamma->modified ) { - r_gamma->modified = qfalse; - - R_IssuePendingRenderCommands(); - R_SetColorMappings(); - } - - // check for errors - if ( !r_ignoreGLErrors->integer ) - { - int err; - - R_IssuePendingRenderCommands(); - if ((err = qglGetError()) != GL_NO_ERROR) - ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err); - } - - if (glConfig.stereoEnabled) { - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - - cmd->commandId = RC_DRAW_BUFFER; - - if ( stereoFrame == STEREO_LEFT ) { - cmd->buffer = (int)GL_BACK_LEFT; - } else if ( stereoFrame == STEREO_RIGHT ) { - cmd->buffer = (int)GL_BACK_RIGHT; - } else { - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame ); - } - } - else - { - if(r_anaglyphMode->integer) - { - if(r_anaglyphMode->modified) - { - // clear both, front and backbuffer. - qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); - - qglDrawBuffer(GL_FRONT); - qglClear(GL_COLOR_BUFFER_BIT); - qglDrawBuffer(GL_BACK); - qglClear(GL_COLOR_BUFFER_BIT); - - r_anaglyphMode->modified = qfalse; - } - - if(stereoFrame == STEREO_LEFT) - { - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - - if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) ) - return; - } - else if(stereoFrame == STEREO_RIGHT) - { - clearDepthCommand_t *cldcmd; - - if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) ) - return; - - cldcmd->commandId = RC_CLEARDEPTH; - - if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) ) - return; - } - else - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame ); - - R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer); - colcmd->commandId = RC_COLORMASK; - } - else - { - if(stereoFrame != STEREO_CENTER) - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame ); - - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - } - - if(cmd) - { - cmd->commandId = RC_DRAW_BUFFER; - - if(r_anaglyphMode->modified) - { - qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - r_anaglyphMode->modified = qfalse; - } - - if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT")) - cmd->buffer = (int)GL_FRONT; - else - cmd->buffer = (int)GL_BACK; - } - } - - tr.refdef.stereoFrame = stereoFrame; -} - - -/* -============= -RE_EndFrame - -Returns the number of msec spent in the back end -============= -*/ -void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) { - swapBuffersCommand_t *cmd; - - if ( !tr.registered ) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SWAP_BUFFERS; - - R_IssueRenderCommands( qtrue ); - - R_InitNextFrame(); - - if ( frontEndMsec ) { - *frontEndMsec = tr.frontEndMsec; - } - tr.frontEndMsec = 0; - if ( backEndMsec ) { - *backEndMsec = backEnd.pc.msec; - } - backEnd.pc.msec = 0; -} - -/* -============= -RE_TakeVideoFrame -============= -*/ -void RE_TakeVideoFrame( int width, int height, - byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ) -{ - videoFrameCommand_t *cmd; - - if( !tr.registered ) { - return; - } - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if( !cmd ) { - return; - } - - cmd->commandId = RC_VIDEOFRAME; - - cmd->width = width; - cmd->height = height; - cmd->captureBuffer = captureBuffer; - cmd->encodeBuffer = encodeBuffer; - cmd->motionJpeg = motionJpeg; -} diff --git a/code/renderergl1/tr_curve.c b/code/renderergl1/tr_curve.c deleted file mode 100644 index 40537eacde..0000000000 --- a/code/renderergl1/tr_curve.c +++ /dev/null @@ -1,625 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -/* - -This file does all of the processing necessary to turn a raw grid of points -read from the map file into a srfGridMesh_t ready for rendering. - -The level of detail solution is direction independent, based only on subdivided -distance from the true curve. - -Only a single entry point: - -srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, - drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { - -*/ - - -/* -============ -LerpDrawVert -============ -*/ -static void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) { - out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]); - out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]); - out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]); - - out->st[0] = 0.5f * (a->st[0] + b->st[0]); - out->st[1] = 0.5f * (a->st[1] + b->st[1]); - - out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]); - out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]); - - out->color[0] = (a->color[0] + b->color[0]) >> 1; - out->color[1] = (a->color[1] + b->color[1]) >> 1; - out->color[2] = (a->color[2] + b->color[2]) >> 1; - out->color[3] = (a->color[3] + b->color[3]) >> 1; -} - -/* -============ -Transpose -============ -*/ -static void Transpose( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j; - drawVert_t temp; - - if ( width > height ) { - for ( i = 0 ; i < height ; i++ ) { - for ( j = i + 1 ; j < width ; j++ ) { - if ( j < height ) { - // swap the value - temp = ctrl[j][i]; - ctrl[j][i] = ctrl[i][j]; - ctrl[i][j] = temp; - } else { - // just copy - ctrl[j][i] = ctrl[i][j]; - } - } - } - } else { - for ( i = 0 ; i < width ; i++ ) { - for ( j = i + 1 ; j < height ; j++ ) { - if ( j < width ) { - // swap the value - temp = ctrl[i][j]; - ctrl[i][j] = ctrl[j][i]; - ctrl[j][i] = temp; - } else { - // just copy - ctrl[i][j] = ctrl[j][i]; - } - } - } - } - -} - - -/* -================= -MakeMeshNormals - -Handles all the complicated wrapping and degenerate cases -================= -*/ -static void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j, k, dist; - vec3_t normal; - vec3_t sum; - int count = 0; - vec3_t base; - vec3_t delta; - int x, y; - drawVert_t *dv; - vec3_t around[8], temp; - qboolean good[8]; - qboolean wrapWidth, wrapHeight; - float len; -static int neighbors[8][2] = { - {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} - }; - - wrapWidth = qfalse; - for ( i = 0 ; i < height ; i++ ) { - VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta ); - len = VectorLengthSquared( delta ); - if ( len > 1.0 ) { - break; - } - } - if ( i == height ) { - wrapWidth = qtrue; - } - - wrapHeight = qfalse; - for ( i = 0 ; i < width ; i++ ) { - VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta ); - len = VectorLengthSquared( delta ); - if ( len > 1.0 ) { - break; - } - } - if ( i == width) { - wrapHeight = qtrue; - } - - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - count = 0; - dv = &ctrl[j][i]; - VectorCopy( dv->xyz, base ); - for ( k = 0 ; k < 8 ; k++ ) { - VectorClear( around[k] ); - good[k] = qfalse; - - for ( dist = 1 ; dist <= 3 ; dist++ ) { - x = i + neighbors[k][0] * dist; - y = j + neighbors[k][1] * dist; - if ( wrapWidth ) { - if ( x < 0 ) { - x = width - 1 + x; - } else if ( x >= width ) { - x = 1 + x - width; - } - } - if ( wrapHeight ) { - if ( y < 0 ) { - y = height - 1 + y; - } else if ( y >= height ) { - y = 1 + y - height; - } - } - - if ( x < 0 || x >= width || y < 0 || y >= height ) { - break; // edge of patch - } - VectorSubtract( ctrl[y][x].xyz, base, temp ); - if ( VectorNormalize2( temp, temp ) == 0 ) { - continue; // degenerate edge, get more dist - } else { - good[k] = qtrue; - VectorCopy( temp, around[k] ); - break; // good edge - } - } - } - - VectorClear( sum ); - for ( k = 0 ; k < 8 ; k++ ) { - if ( !good[k] || !good[(k+1)&7] ) { - continue; // didn't get two points - } - CrossProduct( around[(k+1)&7], around[k], normal ); - if ( VectorNormalize2( normal, normal ) == 0 ) { - continue; - } - VectorAdd( normal, sum, sum ); - count++; - } - //if ( count == 0 ) { - // printf("bad normal\n"); - //} - VectorNormalize2( sum, dv->normal ); - } - } -} - - -/* -============ -InvertCtrl -============ -*/ -static void InvertCtrl( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j; - drawVert_t temp; - - for ( i = 0 ; i < height ; i++ ) { - for ( j = 0 ; j < width/2 ; j++ ) { - temp = ctrl[i][j]; - ctrl[i][j] = ctrl[i][width-1-j]; - ctrl[i][width-1-j] = temp; - } - } -} - - -/* -================= -InvertErrorTable -================= -*/ -static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) { - int i; - float copy[2][MAX_GRID_SIZE]; - - Com_Memcpy( copy, errorTable, sizeof( copy ) ); - - for ( i = 0 ; i < width ; i++ ) { - errorTable[1][i] = copy[0][i]; //[width-1-i]; - } - - for ( i = 0 ; i < height ; i++ ) { - errorTable[0][i] = copy[1][height-1-i]; - } - -} - -/* -================== -PutPointsOnCurve -================== -*/ -static void PutPointsOnCurve( drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], - int width, int height ) { - int i, j; - drawVert_t prev, next; - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 1 ; j < height ; j += 2 ) { - LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev ); - LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next ); - LerpDrawVert( &prev, &next, &ctrl[j][i] ); - } - } - - - for ( j = 0 ; j < height ; j++ ) { - for ( i = 1 ; i < width ; i += 2 ) { - LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev ); - LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next ); - LerpDrawVert( &prev, &next, &ctrl[j][i] ); - } - } -} - -/* -================= -R_CreateSurfaceGridMesh -================= -*/ -srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height, - drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE] ) { - int i, j, size; - drawVert_t *vert; - vec3_t tmpVec; - srfGridMesh_t *grid; - - // copy the results out to a grid - size = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid ); - -#ifdef PATCH_STITCHING - grid = /*ri.Hunk_Alloc*/ ri.Malloc( size ); - Com_Memset(grid, 0, size); - - grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 ); - Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); - - grid->heightLodError = /*ri.Hunk_Alloc*/ ri.Malloc( height * 4 ); - Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); -#else - grid = ri.Hunk_Alloc( size ); - Com_Memset(grid, 0, size); - - grid->widthLodError = ri.Hunk_Alloc( width * 4 ); - Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); - - grid->heightLodError = ri.Hunk_Alloc( height * 4 ); - Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); -#endif - - grid->width = width; - grid->height = height; - grid->surfaceType = SF_GRID; - ClearBounds( grid->meshBounds[0], grid->meshBounds[1] ); - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - vert = &grid->verts[j*width+i]; - *vert = ctrl[j][i]; - AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] ); - } - } - - // compute local origin and bounds - VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin ); - VectorScale( grid->localOrigin, 0.5f, grid->localOrigin ); - VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec ); - grid->meshRadius = VectorLength( tmpVec ); - - VectorCopy( grid->localOrigin, grid->lodOrigin ); - grid->lodRadius = grid->meshRadius; - // - return grid; -} - -/* -================= -R_FreeSurfaceGridMesh -================= -*/ -void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) { - ri.Free(grid->widthLodError); - ri.Free(grid->heightLodError); - ri.Free(grid); -} - -/* -================= -R_SubdividePatchToGrid -================= -*/ -srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, - drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { - int i, j, k, l; - drawVert_t_cleared( prev ); - drawVert_t_cleared( next ); - drawVert_t_cleared( mid ); - float len, maxLen; - int dir; - int t; - drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - ctrl[j][i] = points[j*width+i]; - } - } - - for ( dir = 0 ; dir < 2 ; dir++ ) { - - for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) { - errorTable[dir][j] = 0; - } - - // horizontal subdivisions - for ( j = 0 ; j + 2 < width ; j += 2 ) { - // check subdivided midpoints against control points - - // FIXME: also check midpoints of adjacent patches against the control points - // this would basically stitch all patches in the same LOD group together. - - maxLen = 0; - for ( i = 0 ; i < height ; i++ ) { - vec3_t midxyz; - vec3_t midxyz2; - vec3_t dir; - vec3_t projected; - float d; - - // calculate the point on the curve - for ( l = 0 ; l < 3 ; l++ ) { - midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2 - + ctrl[i][j+2].xyz[l] ) * 0.25f; - } - - // see how far off the line it is - // using dist-from-line will not account for internal - // texture warping, but it gives a lot less polygons than - // dist-from-midpoint - VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz ); - VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir ); - VectorNormalize( dir ); - - d = DotProduct( midxyz, dir ); - VectorScale( dir, d, projected ); - VectorSubtract( midxyz, projected, midxyz2); - len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later - if ( len > maxLen ) { - maxLen = len; - } - } - - maxLen = sqrt(maxLen); - - // if all the points are on the lines, remove the entire columns - if ( maxLen < 0.1f ) { - errorTable[dir][j+1] = 999; - continue; - } - - // see if we want to insert subdivided columns - if ( width + 2 > MAX_GRID_SIZE ) { - errorTable[dir][j+1] = 1.0f/maxLen; - continue; // can't subdivide any more - } - - if ( maxLen <= r_subdivisions->value ) { - errorTable[dir][j+1] = 1.0f/maxLen; - continue; // didn't need subdivision - } - - errorTable[dir][j+2] = 1.0f/maxLen; - - // insert two columns and replace the peak - width += 2; - for ( i = 0 ; i < height ; i++ ) { - LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev ); - LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next ); - LerpDrawVert( &prev, &next, &mid ); - - for ( k = width - 1 ; k > j + 3 ; k-- ) { - ctrl[i][k] = ctrl[i][k-2]; - } - ctrl[i][j + 1] = prev; - ctrl[i][j + 2] = mid; - ctrl[i][j + 3] = next; - } - - // back up and recheck this set again, it may need more subdivision - j -= 2; - - } - - Transpose( width, height, ctrl ); - t = width; - width = height; - height = t; - } - - - // put all the aproximating points on the curve - PutPointsOnCurve( ctrl, width, height ); - - // cull out any rows or columns that are colinear - for ( i = 1 ; i < width-1 ; i++ ) { - if ( errorTable[0][i] != 999 ) { - continue; - } - for ( j = i+1 ; j < width ; j++ ) { - for ( k = 0 ; k < height ; k++ ) { - ctrl[k][j-1] = ctrl[k][j]; - } - errorTable[0][j-1] = errorTable[0][j]; - } - width--; - } - - for ( i = 1 ; i < height-1 ; i++ ) { - if ( errorTable[1][i] != 999 ) { - continue; - } - for ( j = i+1 ; j < height ; j++ ) { - for ( k = 0 ; k < width ; k++ ) { - ctrl[j-1][k] = ctrl[j][k]; - } - errorTable[1][j-1] = errorTable[1][j]; - } - height--; - } - -#if 1 - // flip for longest tristrips as an optimization - // the results should be visually identical with or - // without this step - if ( height > width ) { - Transpose( width, height, ctrl ); - InvertErrorTable( errorTable, width, height ); - t = width; - width = height; - height = t; - InvertCtrl( width, height, ctrl ); - } -#endif - - // calculate normals - MakeMeshNormals( width, height, ctrl ); - - return R_CreateSurfaceGridMesh( width, height, ctrl, errorTable ); -} - -/* -=============== -R_GridInsertColumn -=============== -*/ -srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) { - int i, j; - int width, height, oldwidth; - drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - float lodRadius; - vec3_t lodOrigin; - - oldwidth = 0; - width = grid->width + 1; - if (width > MAX_GRID_SIZE) - return NULL; - height = grid->height; - for (i = 0; i < width; i++) { - if (i == column) { - //insert new column - for (j = 0; j < grid->height; j++) { - LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] ); - if (j == row) - VectorCopy(point, ctrl[j][i].xyz); - } - errorTable[0][i] = loderror; - continue; - } - errorTable[0][i] = grid->widthLodError[oldwidth]; - for (j = 0; j < grid->height; j++) { - ctrl[j][i] = grid->verts[j * grid->width + oldwidth]; - } - oldwidth++; - } - for (j = 0; j < grid->height; j++) { - errorTable[1][j] = grid->heightLodError[j]; - } - // put all the aproximating points on the curve - //PutPointsOnCurve( ctrl, width, height ); - // calculate normals - MakeMeshNormals( width, height, ctrl ); - - VectorCopy(grid->lodOrigin, lodOrigin); - lodRadius = grid->lodRadius; - // free the old grid - R_FreeSurfaceGridMesh(grid); - // create a new grid - grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable ); - grid->lodRadius = lodRadius; - VectorCopy(lodOrigin, grid->lodOrigin); - return grid; -} - -/* -=============== -R_GridInsertRow -=============== -*/ -srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) { - int i, j; - int width, height, oldheight; - drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - float lodRadius; - vec3_t lodOrigin; - - oldheight = 0; - width = grid->width; - height = grid->height + 1; - if (height > MAX_GRID_SIZE) - return NULL; - for (i = 0; i < height; i++) { - if (i == row) { - //insert new row - for (j = 0; j < grid->width; j++) { - LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] ); - if (j == column) - VectorCopy(point, ctrl[i][j].xyz); - } - errorTable[1][i] = loderror; - continue; - } - errorTable[1][i] = grid->heightLodError[oldheight]; - for (j = 0; j < grid->width; j++) { - ctrl[i][j] = grid->verts[oldheight * grid->width + j]; - } - oldheight++; - } - for (j = 0; j < grid->width; j++) { - errorTable[0][j] = grid->widthLodError[j]; - } - // put all the aproximating points on the curve - //PutPointsOnCurve( ctrl, width, height ); - // calculate normals - MakeMeshNormals( width, height, ctrl ); - - VectorCopy(grid->lodOrigin, lodOrigin); - lodRadius = grid->lodRadius; - // free the old grid - R_FreeSurfaceGridMesh(grid); - // create a new grid - grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable ); - grid->lodRadius = lodRadius; - VectorCopy(lodOrigin, grid->lodOrigin); - return grid; -} diff --git a/code/renderergl1/tr_flares.c b/code/renderergl1/tr_flares.c deleted file mode 100644 index 7bd95194f0..0000000000 --- a/code/renderergl1/tr_flares.c +++ /dev/null @@ -1,539 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_flares.c - -#include "tr_local.h" - -/* -============================================================================= - -LIGHT FLARES - -A light flare is an effect that takes place inside the eye when bright light -sources are visible. The size of the flare relative to the screen is nearly -constant, irrespective of distance, but the intensity should be proportional to the -projected area of the light source. - -A surface that has been flagged as having a light flare will calculate the depth -buffer value that its midpoint should have when the surface is added. - -After all opaque surfaces have been rendered, the depth buffer is read back for -each flare in view. If the point has not been obscured by a closer surface, the -flare should be drawn. - -Surfaces that have a repeated texture should never be flagged as flaring, because -there will only be a single flare added at the midpoint of the polygon. - -To prevent abrupt popping, the intensity of the flare is interpolated up and -down as it changes visibility. This involves scene to scene state, unlike almost -all other aspects of the renderer, and is complicated by the fact that a single -frame may have multiple scenes. - -RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially -up to five or more times in a frame with 3D status bar icons). - -============================================================================= -*/ - - -// flare states maintain visibility over multiple frames for fading -// layers: view, mirror, menu -typedef struct flare_s { - struct flare_s *next; // for active chain - - int addedFrame; - - qboolean inPortal; // true if in a portal view of the scene - int frameSceneNum; - void *surface; - int fogNum; - - int fadeTime; - - qboolean visible; // state of last test - float drawIntensity; // may be non 0 even if !visible due to fading - - int windowX, windowY; - float eyeZ; - - vec3_t origin; - vec3_t color; -} flare_t; - -#define MAX_FLARES 256 - -flare_t r_flareStructs[MAX_FLARES]; -flare_t *r_activeFlares, *r_inactiveFlares; - -int flareCoeff; - -/* -================== -R_SetFlareCoeff -================== -*/ -static void R_SetFlareCoeff( void ) { - - if(r_flareCoeff->value == 0.0f) - flareCoeff = atof(FLARE_STDCOEFF); - else - flareCoeff = r_flareCoeff->value; -} - -/* -================== -R_ClearFlares -================== -*/ -void R_ClearFlares( void ) { - int i; - - Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) ); - r_activeFlares = NULL; - r_inactiveFlares = NULL; - - for ( i = 0 ; i < MAX_FLARES ; i++ ) { - r_flareStructs[i].next = r_inactiveFlares; - r_inactiveFlares = &r_flareStructs[i]; - } - - R_SetFlareCoeff(); -} - - -/* -================== -RB_AddFlare - -This is called at surface tesselation time -================== -*/ -void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) { - int i; - flare_t *f; - vec3_t local; - float d = 1; - vec4_t eye, clip, normalized, window; - - backEnd.pc.c_flareAdds++; - - if(normal && (normal[0] || normal[1] || normal[2])) - { - VectorSubtract( backEnd.viewParms.or.origin, point, local ); - VectorNormalizeFast(local); - d = DotProduct(local, normal); - - // If the viewer is behind the flare don't add it. - if(d < 0) - return; - } - - // if the point is off the screen, don't bother adding it - // calculate screen coordinates and depth - R_TransformModelToClip( point, backEnd.or.modelMatrix, - backEnd.viewParms.projectionMatrix, eye, clip ); - - // check to see if the point is completely off screen - for ( i = 0 ; i < 3 ; i++ ) { - if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) { - return; - } - } - - R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window ); - - if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth - || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) { - return; // shouldn't happen, since we check the clip[] above, except for FP rounding - } - - // see if a flare with a matching surface, scene, and view exists - for ( f = r_activeFlares ; f ; f = f->next ) { - if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal ) { - break; - } - } - - // allocate a new one - if (!f ) { - if ( !r_inactiveFlares ) { - // the list is completely full - return; - } - f = r_inactiveFlares; - r_inactiveFlares = r_inactiveFlares->next; - f->next = r_activeFlares; - r_activeFlares = f; - - f->surface = surface; - f->frameSceneNum = backEnd.viewParms.frameSceneNum; - f->inPortal = backEnd.viewParms.isPortal; - f->addedFrame = -1; - } - - if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) { - f->visible = qfalse; - f->fadeTime = backEnd.refdef.time - 2000; - } - - f->addedFrame = backEnd.viewParms.frameCount; - f->fogNum = fogNum; - - VectorCopy(point, f->origin); - VectorCopy( color, f->color ); - - // fade the intensity of the flare down as the - // light surface turns away from the viewer - VectorScale( f->color, d, f->color ); - - // save info needed to test - f->windowX = backEnd.viewParms.viewportX + window[0]; - f->windowY = backEnd.viewParms.viewportY + window[1]; - - f->eyeZ = eye[2]; -} - -/* -================== -RB_AddDlightFlares -================== -*/ -void RB_AddDlightFlares( void ) { - dlight_t *l; - int i, j, k; - fog_t *fog = NULL; - - if ( !r_flares->integer ) { - return; - } - - l = backEnd.refdef.dlights; - - if(tr.world) - fog = tr.world->fogs; - - for (i=0 ; inumfogs ; j++ ) { - fog = &tr.world->fogs[j]; - for ( k = 0 ; k < 3 ; k++ ) { - if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) { - break; - } - } - if ( k == 3 ) { - break; - } - } - if ( j == tr.world->numfogs ) { - j = 0; - } - } - else - j = 0; - - RB_AddFlare( (void *)l, j, l->origin, l->color, NULL ); - } -} - -/* -=============================================================================== - -FLARE BACK END - -=============================================================================== -*/ - -/* -================== -RB_TestFlare -================== -*/ -void RB_TestFlare( flare_t *f ) { - float depth; - qboolean visible; - float fade; - float screenZ; - - backEnd.pc.c_flareTests++; - - // doing a readpixels is as good as doing a glFinish(), so - // don't bother with another sync - glState.finishCalled = qfalse; - - // read back the z buffer contents - qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth ); - - screenZ = backEnd.viewParms.projectionMatrix[14] / - ( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] ); - - visible = ( -f->eyeZ - -screenZ ) < 24; - - if ( visible ) { - if ( !f->visible ) { - f->visible = qtrue; - f->fadeTime = backEnd.refdef.time - 1; - } - fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value; - } else { - if ( f->visible ) { - f->visible = qfalse; - f->fadeTime = backEnd.refdef.time - 1; - } - fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value; - } - - if ( fade < 0 ) { - fade = 0; - } - if ( fade > 1 ) { - fade = 1; - } - - f->drawIntensity = fade; -} - - -/* -================== -RB_RenderFlare -================== -*/ -void RB_RenderFlare( flare_t *f ) { - float size; - vec3_t color; - int iColor[3]; - float distance, intensity, factor; - byte fogFactors[3] = {255, 255, 255}; - - backEnd.pc.c_flareRenders++; - - // We don't want too big values anyways when dividing by distance. - if(f->eyeZ > -1.0f) - distance = 1.0f; - else - distance = -f->eyeZ; - - // calculate the flare size.. - size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance ); - -/* - * This is an alternative to intensity scaling. It changes the size of the flare on screen instead - * with growing distance. See in the description at the top why this is not the way to go. - // size will change ~ 1/r. - size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f)); -*/ - -/* - * As flare sizes stay nearly constant with increasing distance we must decrease the intensity - * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be - * got by considering the ratio of - * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare) - * An important requirement is: - * intensity <= 1 for all distances. - * - * The formula used here to compute the intensity is as follows: - * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2 - * As you can see, the intensity will have a max. of 1 when the distance is 0. - * The coefficient flareCoeff will determine the falloff speed with increasing distance. - */ - - factor = distance + size * sqrt(flareCoeff); - - intensity = flareCoeff * size * size / (factor * factor); - - VectorScale(f->color, f->drawIntensity * intensity, color); - - // Calculations for fogging - if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs) - { - tess.numVertexes = 1; - VectorCopy(f->origin, tess.xyz[0]); - tess.fogNum = f->fogNum; - - RB_CalcModulateColorsByFog(fogFactors); - - // We don't need to render the flare if colors are 0 anyways. - if(!(fogFactors[0] || fogFactors[1] || fogFactors[2])) - return; - } - - iColor[0] = color[0] * fogFactors[0]; - iColor[1] = color[1] * fogFactors[1]; - iColor[2] = color[2] * fogFactors[2]; - - RB_BeginSurface( tr.flareShader, f->fogNum ); - - // FIXME: use quadstamp? - tess.xyz[tess.numVertexes][0] = f->windowX - size; - tess.xyz[tess.numVertexes][1] = f->windowY - size; - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = iColor[0]; - tess.vertexColors[tess.numVertexes][1] = iColor[1]; - tess.vertexColors[tess.numVertexes][2] = iColor[2]; - tess.vertexColors[tess.numVertexes][3] = 255; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX - size; - tess.xyz[tess.numVertexes][1] = f->windowY + size; - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = iColor[0]; - tess.vertexColors[tess.numVertexes][1] = iColor[1]; - tess.vertexColors[tess.numVertexes][2] = iColor[2]; - tess.vertexColors[tess.numVertexes][3] = 255; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX + size; - tess.xyz[tess.numVertexes][1] = f->windowY + size; - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = iColor[0]; - tess.vertexColors[tess.numVertexes][1] = iColor[1]; - tess.vertexColors[tess.numVertexes][2] = iColor[2]; - tess.vertexColors[tess.numVertexes][3] = 255; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX + size; - tess.xyz[tess.numVertexes][1] = f->windowY - size; - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = iColor[0]; - tess.vertexColors[tess.numVertexes][1] = iColor[1]; - tess.vertexColors[tess.numVertexes][2] = iColor[2]; - tess.vertexColors[tess.numVertexes][3] = 255; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 1; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 3; - - RB_EndSurface(); -} - -/* -================== -RB_RenderFlares - -Because flares are simulating an occular effect, they should be drawn after -everything (all views) in the entire frame has been drawn. - -Because of the way portals use the depth buffer to mark off areas, the -needed information would be lost after each view, so we are forced to draw -flares after each view. - -The resulting artifact is that flares in mirrors or portals don't dim properly -when occluded by something in the main view, and portal flares that should -extend past the portal edge will be overwritten. -================== -*/ -void RB_RenderFlares (void) { - flare_t *f; - flare_t **prev; - qboolean draw; - - if ( !r_flares->integer ) { - return; - } - - if(r_flareCoeff->modified) - { - R_SetFlareCoeff(); - r_flareCoeff->modified = qfalse; - } - - // Reset currentEntity to world so that any previously referenced entities - // don't have influence on the rendering of these flares (i.e. RF_ renderer flags). - backEnd.currentEntity = &tr.worldEntity; - backEnd.or = backEnd.viewParms.world; - -// RB_AddDlightFlares(); - - // perform z buffer readback on each flare in this view - draw = qfalse; - prev = &r_activeFlares; - while ( ( f = *prev ) != NULL ) { - // throw out any flares that weren't added last frame - if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) { - *prev = f->next; - f->next = r_inactiveFlares; - r_inactiveFlares = f; - continue; - } - - // don't draw any here that aren't from this scene / portal - f->drawIntensity = 0; - if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal ) { - RB_TestFlare( f ); - if ( f->drawIntensity ) { - draw = qtrue; - } else { - // this flare has completely faded out, so remove it from the chain - *prev = f->next; - f->next = r_inactiveFlares; - r_inactiveFlares = f; - continue; - } - } - - prev = &f->next; - } - - if ( !draw ) { - return; // none visible - } - - if ( backEnd.viewParms.isPortal ) { - qglDisable (GL_CLIP_PLANE0); - } - - qglPushMatrix(); - qglLoadIdentity(); - qglMatrixMode( GL_PROJECTION ); - qglPushMatrix(); - qglLoadIdentity(); - qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, - backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight, - -99999, 99999 ); - - for ( f = r_activeFlares ; f ; f = f->next ) { - if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal - && f->drawIntensity ) { - RB_RenderFlare( f ); - } - } - - qglPopMatrix(); - qglMatrixMode( GL_MODELVIEW ); - qglPopMatrix(); -} - diff --git a/code/renderergl1/tr_image.c b/code/renderergl1/tr_image.c deleted file mode 100644 index d1127829b8..0000000000 --- a/code/renderergl1/tr_image.c +++ /dev/null @@ -1,1682 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_image.c -#include "tr_local.h" - -static byte s_intensitytable[256]; -static unsigned char s_gammatable[256]; - -int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; -int gl_filter_max = GL_LINEAR; - -#define FILE_HASH_SIZE 1024 -static image_t* hashTable[FILE_HASH_SIZE]; - -/* -** R_GammaCorrect -*/ -void R_GammaCorrect( byte *buffer, int bufSize ) { - int i; - - for ( i = 0; i < bufSize; i++ ) { - buffer[i] = s_gammatable[buffer[i]]; - } -} - -typedef struct { - char *name; - int minimize, maximize; -} textureMode_t; - -textureMode_t modes[] = { - {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, - {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, - {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, - {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, - {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, - {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} -}; - -/* -================ -return a hash value for the filename -================ -*/ -static long generateHashValue( const char *fname ) { - int i; - long hash; - char letter; - - hash = 0; - i = 0; - while (fname[i] != '\0') { - letter = tolower(fname[i]); - if (letter =='.') break; // don't include extension - if (letter =='\\') letter = '/'; // damn path names - hash+=(long)(letter)*(i+119); - i++; - } - hash &= (FILE_HASH_SIZE-1); - return hash; -} - -/* -=============== -GL_TextureMode -=============== -*/ -void GL_TextureMode( const char *string ) { - int i; - image_t *glt; - - for ( i=0 ; i< 6 ; i++ ) { - if ( !Q_stricmp( modes[i].name, string ) ) { - break; - } - } - - // hack to prevent trilinear from being set on voodoo, - // because their driver freaks... - if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) { - ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" ); - i = 3; - } - - - if ( i == 6 ) { - ri.Printf (PRINT_ALL, "bad filter name\n"); - return; - } - - gl_filter_min = modes[i].minimize; - gl_filter_max = modes[i].maximize; - - // change all the existing mipmap texture objects - for ( i = 0 ; i < tr.numImages ; i++ ) { - glt = tr.images[ i ]; - if ( glt->flags & IMGFLAG_MIPMAP ) { - GL_Bind (glt); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - } -} - -/* -=============== -R_SumOfUsedImages -=============== -*/ -int R_SumOfUsedImages( void ) { - int total; - int i; - - total = 0; - for ( i = 0; i < tr.numImages; i++ ) { - if ( tr.images[i]->frameUsed == tr.frameCount ) { - total += tr.images[i]->uploadWidth * tr.images[i]->uploadHeight; - } - } - - return total; -} - -/* -=============== -R_ImageList_f -=============== -*/ -void R_ImageList_f( void ) { - int i; - int estTotalSize = 0; - - ri.Printf(PRINT_ALL, "\n -w-- -h-- type -size- --name-------\n"); - - for ( i = 0 ; i < tr.numImages ; i++ ) - { - image_t *image = tr.images[i]; - char *format = "???? "; - char *sizeSuffix; - int estSize; - int displaySize; - - estSize = image->uploadHeight * image->uploadWidth; - - switch(image->internalFormat) - { - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: - format = "sDXT1"; - // 64 bits per 16 pixels, so 4 bits per pixel - estSize /= 2; - break; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - format = "sDXT5"; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB: - format = "sBPTC"; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: - format = "LATC "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - format = "DXT1 "; - // 64 bits per 16 pixels, so 4 bits per pixel - estSize /= 2; - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - format = "DXT5 "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: - format = "BPTC "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_RGB4_S3TC: - format = "S3TC "; - // same as DXT1? - estSize /= 2; - break; - case GL_RGBA4: - case GL_RGBA8: - case GL_RGBA: - format = "RGBA "; - // 4 bytes per pixel - estSize *= 4; - break; - case GL_LUMINANCE8: - case GL_LUMINANCE16: - case GL_LUMINANCE: - format = "L "; - // 1 byte per pixel? - break; - case GL_RGB5: - case GL_RGB8: - case GL_RGB: - format = "RGB "; - // 3 bytes per pixel? - estSize *= 3; - break; - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE16_ALPHA16: - case GL_LUMINANCE_ALPHA: - format = "LA "; - // 2 bytes per pixel? - estSize *= 2; - break; - case GL_SRGB_EXT: - case GL_SRGB8_EXT: - format = "sRGB "; - // 3 bytes per pixel? - estSize *= 3; - break; - case GL_SRGB_ALPHA_EXT: - case GL_SRGB8_ALPHA8_EXT: - format = "sRGBA"; - // 4 bytes per pixel? - estSize *= 4; - break; - case GL_SLUMINANCE_EXT: - case GL_SLUMINANCE8_EXT: - format = "sL "; - // 1 byte per pixel? - break; - case GL_SLUMINANCE_ALPHA_EXT: - case GL_SLUMINANCE8_ALPHA8_EXT: - format = "sLA "; - // 2 byte per pixel? - estSize *= 2; - break; - } - - // mipmap adds about 50% - if (image->flags & IMGFLAG_MIPMAP) - estSize += estSize / 2; - - sizeSuffix = "b "; - displaySize = estSize; - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "kb"; - } - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "Mb"; - } - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "Gb"; - } - - ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName); - estTotalSize += estSize; - } - - ri.Printf (PRINT_ALL, " ---------\n"); - ri.Printf (PRINT_ALL, " approx %i bytes\n", estTotalSize); - ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages ); -} - -//======================================================================= - -/* -================ -ResampleTexture - -Used to resample images in a more general than quartering fashion. - -This will only be filtered properly if the resampled size -is greater than half the original size. - -If a larger shrinking is needed, use the mipmap function -before or after. -================ -*/ -static void ResampleTexture( unsigned *in, int inwidth, int inheight, unsigned *out, - int outwidth, int outheight ) { - int i, j; - unsigned *inrow, *inrow2; - unsigned frac, fracstep; - unsigned p1[2048], p2[2048]; - byte *pix1, *pix2, *pix3, *pix4; - - if (outwidth>2048) - ri.Error(ERR_DROP, "ResampleTexture: max width"); - - fracstep = inwidth*0x10000/outwidth; - - frac = fracstep>>2; - for ( i=0 ; i>16); - frac += fracstep; - } - frac = 3*(fracstep>>2); - for ( i=0 ; i>16); - frac += fracstep; - } - - for (i=0 ; i>2; - ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; - ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; - ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; - } - } -} - -/* -================ -R_LightScaleTexture - -Scale up the pixel values in a texture to increase the -lighting range -================ -*/ -void R_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma ) -{ - if ( only_gamma ) - { - if ( !glConfig.deviceSupportsGamma ) - { - int i, c; - byte *p; - - p = (byte *)in; - - c = inwidth*inheight; - for (i=0 ; i> 1; - outHeight = inHeight >> 1; - temp = ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 ); - - inWidthMask = inWidth - 1; - inHeightMask = inHeight - 1; - - for ( i = 0 ; i < outHeight ; i++ ) { - for ( j = 0 ; j < outWidth ; j++ ) { - outpix = (byte *) ( temp + i * outWidth + j ); - for ( k = 0 ; k < 4 ; k++ ) { - total = - 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + - 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + - - 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + - 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + - 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + - - 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + - 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + - 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + - - 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + - 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k]; - outpix[k] = total / 36; - } - } - } - - Com_Memcpy( in, temp, outWidth * outHeight * 4 ); - ri.Hunk_FreeTempMemory( temp ); -} - -/* -================ -R_MipMap - -Operates in place, quartering the size of the texture -================ -*/ -static void R_MipMap (byte *in, int width, int height) { - int i, j; - byte *out; - int row; - - if ( !r_simpleMipMaps->integer ) { - R_MipMap2( (unsigned *)in, width, height ); - return; - } - - if ( width == 1 && height == 1 ) { - return; - } - - row = width * 4; - out = in; - width >>= 1; - height >>= 1; - - if ( width == 0 || height == 0 ) { - width += height; // get largest - for (i=0 ; i>1; - out[1] = ( in[1] + in[5] )>>1; - out[2] = ( in[2] + in[6] )>>1; - out[3] = ( in[3] + in[7] )>>1; - } - return; - } - - for (i=0 ; i>2; - out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2; - out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2; - out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2; - } - } -} - - -/* -================== -R_BlendOverTexture - -Apply a color blend over a set of pixels -================== -*/ -static void R_BlendOverTexture( byte *data, int pixelCount, byte blend[4] ) { - int i; - int inverseAlpha; - int premult[3]; - - inverseAlpha = 255 - blend[3]; - premult[0] = blend[0] * blend[3]; - premult[1] = blend[1] * blend[3]; - premult[2] = blend[2] * blend[3]; - - for ( i = 0 ; i < pixelCount ; i++, data+=4 ) { - data[0] = ( data[0] * inverseAlpha + premult[0] ) >> 9; - data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9; - data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9; - } -} - -byte mipBlendColors[16][4] = { - {0,0,0,0}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, -}; - - -/* -=============== -Upload32 - -=============== -*/ -extern qboolean charSet; -static void Upload32( unsigned *data, - int width, int height, - qboolean mipmap, - qboolean picmip, - qboolean lightMap, - int *format, - int *pUploadWidth, int *pUploadHeight ) -{ - int samples; - unsigned *scaledBuffer = NULL; - unsigned *resampledBuffer = NULL; - int scaled_width, scaled_height; - int i, c; - byte *scan; - GLenum internalFormat = GL_RGB; - float rMax = 0, gMax = 0, bMax = 0; - - // - // convert to exact power of 2 sizes - // - for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) - ; - for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) - ; - if ( r_roundImagesDown->integer && scaled_width > width ) - scaled_width >>= 1; - if ( r_roundImagesDown->integer && scaled_height > height ) - scaled_height >>= 1; - - if ( scaled_width != width || scaled_height != height ) { - resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 ); - ResampleTexture (data, width, height, resampledBuffer, scaled_width, scaled_height); - data = resampledBuffer; - width = scaled_width; - height = scaled_height; - } - - // - // perform optional picmip operation - // - if ( picmip ) { - scaled_width >>= r_picmip->integer; - scaled_height >>= r_picmip->integer; - } - - // - // clamp to minimum size - // - if (scaled_width < 1) { - scaled_width = 1; - } - if (scaled_height < 1) { - scaled_height = 1; - } - - // - // clamp to the current upper OpenGL limit - // scale both axis down equally so we don't have to - // deal with a half mip resampling - // - while ( scaled_width > glConfig.maxTextureSize - || scaled_height > glConfig.maxTextureSize ) { - scaled_width >>= 1; - scaled_height >>= 1; - } - - scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height ); - - // - // scan the texture for each channel's max values - // and verify if the alpha channel is being used or not - // - c = width*height; - scan = ((byte *)data); - samples = 3; - - if( r_greyscale->integer ) - { - for ( i = 0; i < c; i++ ) - { - byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = luma; - scan[i*4 + 1] = luma; - scan[i*4 + 2] = luma; - } - } - else if( r_greyscale->value ) - { - for ( i = 0; i < c; i++ ) - { - float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value); - scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value); - scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value); - } - } - - if(lightMap) - { - if(r_greyscale->integer) - internalFormat = GL_LUMINANCE; - else - internalFormat = GL_RGB; - } - else - { - for ( i = 0; i < c; i++ ) - { - if ( scan[i*4+0] > rMax ) - { - rMax = scan[i*4+0]; - } - if ( scan[i*4+1] > gMax ) - { - gMax = scan[i*4+1]; - } - if ( scan[i*4+2] > bMax ) - { - bMax = scan[i*4+2]; - } - if ( scan[i*4 + 3] != 255 ) - { - samples = 4; - break; - } - } - // select proper internal format - if ( samples == 3 ) - { - if(r_greyscale->integer) - { - if(r_texturebits->integer == 16) - internalFormat = GL_LUMINANCE8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16; - else - internalFormat = GL_LUMINANCE; - } - else - { - if ( glConfig.textureCompression == TC_S3TC_ARB ) - { - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - } - else if ( glConfig.textureCompression == TC_S3TC ) - { - internalFormat = GL_RGB4_S3TC; - } - else if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGB5; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGB8; - } - else - { - internalFormat = GL_RGB; - } - } - } - else if ( samples == 4 ) - { - if(r_greyscale->integer) - { - if(r_texturebits->integer == 16) - internalFormat = GL_LUMINANCE8_ALPHA8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16_ALPHA16; - else - internalFormat = GL_LUMINANCE_ALPHA; - } - else - { - if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGBA4; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGBA8; - } - else - { - internalFormat = GL_RGBA; - } - } - } - } - - // copy or resample data as appropriate for first MIP level - if ( ( scaled_width == width ) && - ( scaled_height == height ) ) { - if (!mipmap) - { - qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - *format = internalFormat; - - goto done; - } - Com_Memcpy (scaledBuffer, data, width*height*4); - } - else - { - // use the normal mip-mapping function to go down from here - while ( width > scaled_width || height > scaled_height ) { - R_MipMap( (byte *)data, width, height ); - width >>= 1; - height >>= 1; - if ( width < 1 ) { - width = 1; - } - if ( height < 1 ) { - height = 1; - } - } - Com_Memcpy( scaledBuffer, data, width * height * 4 ); - } - - R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !mipmap ); - - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - *format = internalFormat; - - qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); - - if (mipmap) - { - int miplevel; - - miplevel = 0; - while (scaled_width > 1 || scaled_height > 1) - { - R_MipMap( (byte *)scaledBuffer, scaled_width, scaled_height ); - scaled_width >>= 1; - scaled_height >>= 1; - if (scaled_width < 1) - scaled_width = 1; - if (scaled_height < 1) - scaled_height = 1; - miplevel++; - - if ( r_colorMipLevels->integer ) { - R_BlendOverTexture( (byte *)scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] ); - } - - qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); - } - } -done: - - if (mipmap) - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - (GLint)Com_Clamp( 1, maxAnisotropy, r_ext_max_anisotropy->integer ) ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - else - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - - GL_CheckErrors(); - - if ( scaledBuffer != 0 ) - ri.Hunk_FreeTempMemory( scaledBuffer ); - if ( resampledBuffer != 0 ) - ri.Hunk_FreeTempMemory( resampledBuffer ); -} - - -/* -================ -R_CreateImage - -This is the only way any image_t are created -================ -*/ -image_t *R_CreateImage( const char *name, byte *pic, int width, int height, - imgType_t type, imgFlags_t flags, int internalFormat ) { - image_t *image; - qboolean isLightmap = qfalse; - long hash; - int glWrapClampMode; - - if (strlen(name) >= MAX_QPATH ) { - ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name); - } - if ( !strncmp( name, "*lightmap", 9 ) ) { - isLightmap = qtrue; - } - - if ( tr.numImages == MAX_DRAWIMAGES ) { - ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit"); - } - - image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low ); - image->texnum = 1024 + tr.numImages; - tr.numImages++; - - image->type = type; - image->flags = flags; - - strcpy (image->imgName, name); - - image->width = width; - image->height = height; - if (flags & IMGFLAG_CLAMPTOEDGE) - glWrapClampMode = GL_CLAMP_TO_EDGE; - else - glWrapClampMode = GL_REPEAT; - - // lightmaps are always allocated on TMU 1 - if ( qglActiveTextureARB && isLightmap ) { - image->TMU = 1; - } else { - image->TMU = 0; - } - - if ( qglActiveTextureARB ) { - GL_SelectTexture( image->TMU ); - } - - GL_Bind(image); - - Upload32( (unsigned *)pic, image->width, image->height, - image->flags & IMGFLAG_MIPMAP, - image->flags & IMGFLAG_PICMIP, - isLightmap, - &image->internalFormat, - &image->uploadWidth, - &image->uploadHeight ); - - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode ); - - // FIXME: this stops fog from setting border color? - glState.currenttextures[glState.currenttmu] = 0; - qglBindTexture( GL_TEXTURE_2D, 0 ); - - if ( image->TMU == 1 ) { - GL_SelectTexture( 0 ); - } - - hash = generateHashValue(name); - image->next = hashTable[hash]; - hashTable[hash] = image; - - return image; -} - -//=================================================================== - -typedef struct -{ - char *ext; - void (*ImageLoader)( const char *, unsigned char **, int *, int * ); -} imageExtToLoaderMap_t; - -// Note that the ordering indicates the order of preference used -// when there are multiple images of different formats available -static imageExtToLoaderMap_t imageLoaders[ ] = -{ - { "tga", R_LoadTGA }, - { "jpg", R_LoadJPG }, - { "jpeg", R_LoadJPG }, - { "png", R_LoadPNG }, - { "pcx", R_LoadPCX }, - { "bmp", R_LoadBMP } -}; - -static int numImageLoaders = ARRAY_LEN( imageLoaders ); - -/* -================= -R_LoadImage - -Loads any of the supported image types into a cannonical -32 bit format. -================= -*/ -void R_LoadImage( const char *name, byte **pic, int *width, int *height ) -{ - qboolean orgNameFailed = qfalse; - int orgLoader = -1; - int i; - char localName[ MAX_QPATH ]; - const char *ext; - char *altName; - - *pic = NULL; - *width = 0; - *height = 0; - - Q_strncpyz( localName, name, MAX_QPATH ); - - ext = COM_GetExtension( localName ); - - if( *ext ) - { - // Look for the correct loader and use it - for( i = 0; i < numImageLoaders; i++ ) - { - if( !Q_stricmp( ext, imageLoaders[ i ].ext ) ) - { - // Load - imageLoaders[ i ].ImageLoader( localName, pic, width, height ); - break; - } - } - - // A loader was found - if( i < numImageLoaders ) - { - if( *pic == NULL ) - { - // Loader failed, most likely because the file isn't there; - // try again without the extension - orgNameFailed = qtrue; - orgLoader = i; - COM_StripExtension( name, localName, MAX_QPATH ); - } - else - { - // Something loaded - return; - } - } - } - - // Try and find a suitable match using all - // the image formats supported - for( i = 0; i < numImageLoaders; i++ ) - { - if (i == orgLoader) - continue; - - altName = va( "%s.%s", localName, imageLoaders[ i ].ext ); - - // Load - imageLoaders[ i ].ImageLoader( altName, pic, width, height ); - - if( *pic ) - { - if( orgNameFailed ) - { - ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n", - name, altName ); - } - - break; - } - } -} - - -/* -=============== -R_FindImageFile - -Finds or loads the given image. -Returns NULL if it fails, not a default image. -============== -*/ -image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) -{ - image_t *image; - int width, height; - byte *pic; - long hash; - - if (!name) { - return NULL; - } - - hash = generateHashValue(name); - - // - // see if the image is already loaded - // - for (image=hashTable[hash]; image; image=image->next) { - if ( !strcmp( name, image->imgName ) ) { - // the white image can be used with any set of parms, but other mismatches are errors - if ( strcmp( name, "*white" ) ) { - if ( image->flags != flags ) { - ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed flags (%i vs %i)\n", name, image->flags, flags ); - } - } - return image; - } - } - - // - // load the pic from disk - // - R_LoadImage( name, &pic, &width, &height ); - if ( pic == NULL ) { - return NULL; - } - - image = R_CreateImage( ( char * ) name, pic, width, height, type, flags, 0 ); - ri.Free( pic ); - return image; -} - - -/* -================ -R_CreateDlightImage -================ -*/ -#define DLIGHT_SIZE 16 -static void R_CreateDlightImage( void ) { - int x,y; - byte data[DLIGHT_SIZE][DLIGHT_SIZE][4]; - int b; - - // make a centered inverse-square falloff blob for dynamic lighting - for (x=0 ; x 255) { - b = 255; - } else if ( b < 75 ) { - b = 0; - } - data[y][x][0] = - data[y][x][1] = - data[y][x][2] = b; - data[y][x][3] = 255; - } - } - tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 ); -} - - -/* -================= -R_InitFogTable -================= -*/ -void R_InitFogTable( void ) { - int i; - float d; - float exp; - - exp = 0.5; - - for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) { - d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp ); - - tr.fogTable[i] = d; - } -} - -/* -================ -R_FogFactor - -Returns a 0.0 to 1.0 fog density value -This is called for each texel of the fog texture on startup -and for each vertex of transparent shaders in fog dynamically -================ -*/ -float R_FogFactor( float s, float t ) { - float d; - - s -= 1.0/512; - if ( s < 0 ) { - return 0; - } - if ( t < 1.0/32 ) { - return 0; - } - if ( t < 31.0/32 ) { - s *= (t - 1.0f/32.0f) / (30.0f/32.0f); - } - - // we need to leave a lot of clamp range - s *= 8; - - if ( s > 1.0 ) { - s = 1.0; - } - - d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ]; - - return d; -} - -/* -================ -R_CreateFogImage -================ -*/ -#define FOG_S 256 -#define FOG_T 32 -static void R_CreateFogImage( void ) { - int x,y; - byte *data; - float d; - float borderColor[4]; - - data = ri.Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 ); - - // S is distance, T is depth - for (x=0 ; xinteger; - if ( !glConfig.deviceSupportsGamma ) { - tr.overbrightBits = 0; // need hardware gamma for overbright - } - - // never overbright in windowed mode - if ( !glConfig.isFullscreen ) - { - tr.overbrightBits = 0; - } - - // allow 2 overbright bits in 24 bit, but only 1 in 16 bit - if ( glConfig.colorBits > 16 ) { - if ( tr.overbrightBits > 2 ) { - tr.overbrightBits = 2; - } - } else { - if ( tr.overbrightBits > 1 ) { - tr.overbrightBits = 1; - } - } - if ( tr.overbrightBits < 0 ) { - tr.overbrightBits = 0; - } - - tr.identityLight = 1.0f / ( 1 << tr.overbrightBits ); - tr.identityLightByte = 255 * tr.identityLight; - - - if ( r_intensity->value <= 1 ) { - ri.Cvar_Set( "r_intensity", "1" ); - } - - if ( r_gamma->value < 0.5f ) { - ri.Cvar_Set( "r_gamma", "0.5" ); - } else if ( r_gamma->value > 3.0f ) { - ri.Cvar_Set( "r_gamma", "3.0" ); - } - - g = r_gamma->value; - - shift = tr.overbrightBits; - - for ( i = 0; i < 256; i++ ) { - if ( g == 1 ) { - inf = i; - } else { - inf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f; - } - inf <<= shift; - if (inf < 0) { - inf = 0; - } - if (inf > 255) { - inf = 255; - } - s_gammatable[i] = inf; - } - - for (i=0 ; i<256 ; i++) { - j = i * r_intensity->value; - if (j > 255) { - j = 255; - } - s_intensitytable[i] = j; - } - - if ( glConfig.deviceSupportsGamma ) - { - GLimp_SetGamma( s_gammatable, s_gammatable, s_gammatable ); - } -} - -/* -=============== -R_InitImages -=============== -*/ -void R_InitImages( void ) { - Com_Memset(hashTable, 0, sizeof(hashTable)); - // build brightness translation tables - R_SetColorMappings(); - - // create default texture and white texture - R_CreateBuiltinImages(); -} - -/* -=============== -R_DeleteTextures -=============== -*/ -void R_DeleteTextures( void ) { - int i; - - for ( i=0; itexnum ); - } - Com_Memset( tr.images, 0, sizeof( tr.images ) ); - - tr.numImages = 0; - - Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) ); - if ( qglActiveTextureARB ) { - GL_SelectTexture( 1 ); - qglBindTexture( GL_TEXTURE_2D, 0 ); - GL_SelectTexture( 0 ); - qglBindTexture( GL_TEXTURE_2D, 0 ); - } else { - qglBindTexture( GL_TEXTURE_2D, 0 ); - } -} - -/* -============================================================================ - -SKINS - -============================================================================ -*/ - -/* -================== -CommaParse - -This is unfortunate, but the skin files aren't -compatable with our normal parsing rules. -================== -*/ -static char *CommaParse( char **data_p ) { - int c = 0, len; - char *data; - static char com_token[MAX_TOKEN_CHARS]; - - data = *data_p; - len = 0; - com_token[0] = 0; - - // make sure incoming data is valid - if ( !data ) { - *data_p = NULL; - return com_token; - } - - while ( 1 ) { - // skip whitespace - while( (c = *data) <= ' ') { - if( !c ) { - break; - } - data++; - } - - - c = *data; - - // skip double slash comments - if ( c == '/' && data[1] == '/' ) - { - while (*data && *data != '\n') - data++; - } - // skip /* */ comments - else if ( c=='/' && data[1] == '*' ) - { - while ( *data && ( *data != '*' || data[1] != '/' ) ) - { - data++; - } - if ( *data ) - { - data += 2; - } - } - else - { - break; - } - } - - if ( c == 0 ) { - return ""; - } - - // handle quoted strings - if (c == '\"') - { - data++; - while (1) - { - c = *data++; - if (c=='\"' || !c) - { - com_token[len] = 0; - *data_p = ( char * ) data; - return com_token; - } - if (len < MAX_TOKEN_CHARS) - { - com_token[len] = c; - len++; - } - } - } - - // parse a regular word - do - { - if (len < MAX_TOKEN_CHARS) - { - com_token[len] = c; - len++; - } - data++; - c = *data; - } while (c>32 && c != ',' ); - - if (len == MAX_TOKEN_CHARS) - { -// ri.Printf (PRINT_DEVELOPER, "Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS); - len = 0; - } - com_token[len] = 0; - - *data_p = ( char * ) data; - return com_token; -} - - -/* -=============== -RE_RegisterSkin - -=============== -*/ -qhandle_t RE_RegisterSkin( const char *name ) { - qhandle_t hSkin; - skin_t *skin; - skinSurface_t *surf; - union { - char *c; - void *v; - } text; - char *text_p; - char *token; - char surfName[MAX_QPATH]; - - if ( !name || !name[0] ) { - ri.Printf( PRINT_DEVELOPER, "Empty name passed to RE_RegisterSkin\n" ); - return 0; - } - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_DEVELOPER, "Skin name exceeds MAX_QPATH\n" ); - return 0; - } - - - // see if the skin is already loaded - for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) { - skin = tr.skins[hSkin]; - if ( !Q_stricmp( skin->name, name ) ) { - if( skin->numSurfaces == 0 ) { - return 0; // default skin - } - return hSkin; - } - } - - // allocate a new skin - if ( tr.numSkins == MAX_SKINS ) { - ri.Printf( PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name ); - return 0; - } - tr.numSkins++; - skin = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); - tr.skins[hSkin] = skin; - Q_strncpyz( skin->name, name, sizeof( skin->name ) ); - skin->numSurfaces = 0; - - R_IssuePendingRenderCommands(); - - // If not a .skin file, load as a single shader - if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) { - skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof(skin->surfaces[0]), h_low ); - skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue ); - return hSkin; - } - - // load and parse the skin file - ri.FS_ReadFile( name, &text.v ); - if ( !text.c ) { - return 0; - } - - text_p = text.c; - while ( text_p && *text_p ) { - // get surface name - token = CommaParse( &text_p ); - Q_strncpyz( surfName, token, sizeof( surfName ) ); - - if ( !token[0] ) { - break; - } - // lowercase the surface name so skin compares are faster - Q_strlwr( surfName ); - - if ( *text_p == ',' ) { - text_p++; - } - - if ( strstr( token, "tag_" ) ) { - continue; - } - - // parse the shader name - token = CommaParse( &text_p ); - - if ( skin->numSurfaces >= MD3_MAX_SURFACES ) { - ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MD3_MAX_SURFACES ); - break; - } - - surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); - Q_strncpyz( surf->name, surfName, sizeof( surf->name ) ); - surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue ); - skin->numSurfaces++; - } - - ri.FS_FreeFile( text.v ); - - - // never let a skin have 0 shaders - if ( skin->numSurfaces == 0 ) { - return 0; // use default skin - } - - return hSkin; -} - - -/* -=============== -R_InitSkins -=============== -*/ -void R_InitSkins( void ) { - skin_t *skin; - - tr.numSkins = 1; - - // make the default skin have all default shaders - skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); - Q_strncpyz( skin->name, "", sizeof( skin->name ) ); - skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low ); - skin->surfaces[0]->shader = tr.defaultShader; -} - -/* -=============== -R_GetSkinByHandle -=============== -*/ -skin_t *R_GetSkinByHandle( qhandle_t hSkin ) { - if ( hSkin < 1 || hSkin >= tr.numSkins ) { - return tr.skins[0]; - } - return tr.skins[ hSkin ]; -} - -/* -=============== -R_SkinList_f -=============== -*/ -void R_SkinList_f( void ) { - int i, j; - skin_t *skin; - - ri.Printf (PRINT_ALL, "------------------\n"); - - for ( i = 0 ; i < tr.numSkins ; i++ ) { - skin = tr.skins[i]; - - ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name ); - for ( j = 0 ; j < skin->numSurfaces ; j++ ) { - ri.Printf( PRINT_ALL, " %s = %s\n", - skin->surfaces[j]->name, skin->surfaces[j]->shader->name ); - } - } - ri.Printf (PRINT_ALL, "------------------\n"); -} - diff --git a/code/renderergl1/tr_init.c b/code/renderergl1/tr_init.c deleted file mode 100644 index 2a934e93b9..0000000000 --- a/code/renderergl1/tr_init.c +++ /dev/null @@ -1,1370 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_init.c -- functions that are not called every frame - -#include "tr_local.h" - -glconfig_t glConfig; -qboolean textureFilterAnisotropic = qfalse; -int maxAnisotropy = 0; -float displayAspect = 0.0f; - -glstate_t glState; - -static void GfxInfo_f( void ); - -#ifdef USE_RENDERER_DLOPEN -cvar_t *com_altivec; -#endif - -cvar_t *r_flareSize; -cvar_t *r_flareFade; -cvar_t *r_flareCoeff; - -cvar_t *r_railWidth; -cvar_t *r_railCoreWidth; -cvar_t *r_railSegmentLength; - -cvar_t *r_ignoreFastPath; - -cvar_t *r_verbose; -cvar_t *r_ignore; - -cvar_t *r_detailTextures; - -cvar_t *r_znear; -cvar_t *r_zproj; -cvar_t *r_stereoSeparation; - -cvar_t *r_skipBackEnd; - -cvar_t *r_stereoEnabled; -cvar_t *r_anaglyphMode; - -cvar_t *r_greyscale; - -cvar_t *r_ignorehwgamma; -cvar_t *r_measureOverdraw; - -cvar_t *r_inGameVideo; -cvar_t *r_fastsky; -cvar_t *r_drawSun; -cvar_t *r_dynamiclight; -cvar_t *r_dlightBacks; - -cvar_t *r_lodbias; -cvar_t *r_lodscale; - -cvar_t *r_norefresh; -cvar_t *r_drawentities; -cvar_t *r_drawworld; -cvar_t *r_speeds; -cvar_t *r_fullbright; -cvar_t *r_novis; -cvar_t *r_nocull; -cvar_t *r_facePlaneCull; -cvar_t *r_showcluster; -cvar_t *r_nocurves; - -cvar_t *r_allowExtensions; - -cvar_t *r_ext_compressed_textures; -cvar_t *r_ext_multitexture; -cvar_t *r_ext_compiled_vertex_array; -cvar_t *r_ext_texture_env_add; -cvar_t *r_ext_texture_filter_anisotropic; -cvar_t *r_ext_max_anisotropy; - -cvar_t *r_ignoreGLErrors; -cvar_t *r_logFile; - -cvar_t *r_stencilbits; -cvar_t *r_depthbits; -cvar_t *r_colorbits; -cvar_t *r_primitives; -cvar_t *r_texturebits; -cvar_t *r_ext_multisample; - -cvar_t *r_drawBuffer; -cvar_t *r_lightmap; -cvar_t *r_vertexLight; -cvar_t *r_uiFullScreen; -cvar_t *r_shadows; -cvar_t *r_flares; -cvar_t *r_mode; -cvar_t *r_nobind; -cvar_t *r_singleShader; -cvar_t *r_roundImagesDown; -cvar_t *r_colorMipLevels; -cvar_t *r_picmip; -cvar_t *r_showtris; -cvar_t *r_showsky; -cvar_t *r_shownormals; -cvar_t *r_finish; -cvar_t *r_clear; -cvar_t *r_swapInterval; -cvar_t *r_textureMode; -cvar_t *r_offsetFactor; -cvar_t *r_offsetUnits; -cvar_t *r_gamma; -cvar_t *r_intensity; -cvar_t *r_lockpvs; -cvar_t *r_noportals; -cvar_t *r_portalOnly; - -cvar_t *r_subdivisions; -cvar_t *r_lodCurveError; - -cvar_t *r_fullscreen; -cvar_t *r_noborder; - -cvar_t *r_customwidth; -cvar_t *r_customheight; -cvar_t *r_customPixelAspect; - -cvar_t *r_overBrightBits; -cvar_t *r_mapOverBrightBits; - -cvar_t *r_debugSurface; -cvar_t *r_simpleMipMaps; - -cvar_t *r_showImages; - -cvar_t *r_ambientScale; -cvar_t *r_directedScale; -cvar_t *r_debugLight; -cvar_t *r_debugSort; -cvar_t *r_printShaders; -cvar_t *r_saveFontData; - -cvar_t *r_marksOnTriangleMeshes; - -cvar_t *r_aviMotionJpegQuality; -cvar_t *r_screenshotJpegQuality; - -cvar_t *r_maxpolys; -int max_polys; -cvar_t *r_maxpolyverts; -int max_polyverts; - -/* -** InitOpenGL -** -** This function is responsible for initializing a valid OpenGL subsystem. This -** is done by calling GLimp_Init (which gives us a working OGL subsystem) then -** setting variables, checking GL constants, and reporting the gfx system config -** to the user. -*/ -static void InitOpenGL( void ) -{ - char renderer_buffer[1024]; - - // - // initialize OS specific portions of the renderer - // - // GLimp_Init directly or indirectly references the following cvars: - // - r_fullscreen - // - r_mode - // - r_(color|depth|stencil)bits - // - r_ignorehwgamma - // - r_gamma - // - - if ( glConfig.vidWidth == 0 ) - { - GLint temp; - - GLimp_Init(); - - strcpy( renderer_buffer, glConfig.renderer_string ); - Q_strlwr( renderer_buffer ); - - // OpenGL driver constants - qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp ); - glConfig.maxTextureSize = temp; - - // stubbed or broken drivers may have reported 0... - if ( glConfig.maxTextureSize <= 0 ) - { - glConfig.maxTextureSize = 0; - } - } - - // set default state - GL_SetDefaultState(); -} - -/* -================== -GL_CheckErrors -================== -*/ -void GL_CheckErrors( void ) { - int err; - char s[64]; - - err = qglGetError(); - if ( err == GL_NO_ERROR ) { - return; - } - if ( r_ignoreGLErrors->integer ) { - return; - } - switch( err ) { - case GL_INVALID_ENUM: - strcpy( s, "GL_INVALID_ENUM" ); - break; - case GL_INVALID_VALUE: - strcpy( s, "GL_INVALID_VALUE" ); - break; - case GL_INVALID_OPERATION: - strcpy( s, "GL_INVALID_OPERATION" ); - break; - case GL_STACK_OVERFLOW: - strcpy( s, "GL_STACK_OVERFLOW" ); - break; - case GL_STACK_UNDERFLOW: - strcpy( s, "GL_STACK_UNDERFLOW" ); - break; - case GL_OUT_OF_MEMORY: - strcpy( s, "GL_OUT_OF_MEMORY" ); - break; - default: - Com_sprintf( s, sizeof(s), "%i", err); - break; - } - - ri.Error( ERR_FATAL, "GL_CheckErrors: %s", s ); -} - - -/* -** R_GetModeInfo -*/ -typedef struct vidmode_s -{ - const char *description; - int width, height; - float pixelAspect; // pixel width / height -} vidmode_t; - -vidmode_t r_vidModes[] = -{ - { "Mode 0: 320x240", 320, 240, 1 }, - { "Mode 1: 400x300", 400, 300, 1 }, - { "Mode 2: 512x384", 512, 384, 1 }, - { "Mode 3: 640x480", 640, 480, 1 }, - { "Mode 4: 800x600", 800, 600, 1 }, - { "Mode 5: 960x720", 960, 720, 1 }, - { "Mode 6: 1024x768", 1024, 768, 1 }, - { "Mode 7: 1152x864", 1152, 864, 1 }, - { "Mode 8: 1280x1024", 1280, 1024, 1 }, - { "Mode 9: 1600x1200", 1600, 1200, 1 }, - { "Mode 10: 2048x1536", 2048, 1536, 1 }, - { "Mode 11: 856x480 (wide)",856, 480, 1 } -}; -static int s_numVidModes = ARRAY_LEN( r_vidModes ); - -qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ) { - vidmode_t *vm; - float pixelAspect; - - if ( mode < -1 ) { - return qfalse; - } - if ( mode >= s_numVidModes ) { - return qfalse; - } - - if ( mode == -1 ) { - *width = r_customwidth->integer; - *height = r_customheight->integer; - pixelAspect = r_customPixelAspect->value; - } else { - vm = &r_vidModes[mode]; - - *width = vm->width; - *height = vm->height; - pixelAspect = vm->pixelAspect; - } - - *windowAspect = (float)*width / ( *height * pixelAspect ); - - return qtrue; -} - -/* -** R_ModeList_f -*/ -static void R_ModeList_f( void ) -{ - int i; - - ri.Printf( PRINT_ALL, "\n" ); - for ( i = 0; i < s_numVidModes; i++ ) - { - ri.Printf( PRINT_ALL, "%s\n", r_vidModes[i].description ); - } - ri.Printf( PRINT_ALL, "\n" ); -} - - -/* -============================================================================== - - SCREEN SHOTS - -NOTE TTimo -some thoughts about the screenshots system: -screenshots get written in fs_homepath + fs_gamedir -vanilla q3 .. baseq3/screenshots/ *.tga -team arena .. missionpack/screenshots/ *.tga - -two commands: "screenshot" and "screenshotJPEG" -we use statics to store a count and start writing the first screenshot/screenshot????.tga (.jpg) available -(with FS_FileExists / FS_FOpenFileWrite calls) -FIXME: the statics don't get a reinit between fs_game changes - -============================================================================== -*/ - -/* -================== -RB_ReadPixels - -Reads an image but takes care of alignment issues for reading RGB images. - -Reads a minimum offset for where the RGB data starts in the image from -integer stored at pointer offset. When the function has returned the actual -offset was written back to address offset. This address will always have an -alignment of packAlign to ensure efficient copying. - -Stores the length of padding after a line of pixels to address padlen - -Return value must be freed with ri.Hunk_FreeTempMemory() -================== -*/ - -byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *padlen) -{ - byte *buffer, *bufstart; - int padwidth, linelen; - GLint packAlign; - - qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); - - linelen = width * 3; - padwidth = PAD(linelen, packAlign); - - // Allocate a few more bytes so that we can choose an alignment we like - buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1); - - bufstart = PADP((intptr_t) buffer + *offset, packAlign); - qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart); - - *offset = bufstart - buffer; - *padlen = padwidth - linelen; - - return buffer; -} - -/* -================== -RB_TakeScreenshot -================== -*/ -void RB_TakeScreenshot(int x, int y, int width, int height, char *fileName) -{ - byte *allbuf, *buffer; - byte *srcptr, *destptr; - byte *endline, *endmem; - byte temp; - - int linelen, padlen; - size_t offset = 18, memcount; - - allbuf = RB_ReadPixels(x, y, width, height, &offset, &padlen); - buffer = allbuf + offset - 18; - - Com_Memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = width & 255; - buffer[13] = width >> 8; - buffer[14] = height & 255; - buffer[15] = height >> 8; - buffer[16] = 24; // pixel size - - // swap rgb to bgr and remove padding from line endings - linelen = width * 3; - - srcptr = destptr = allbuf + offset; - endmem = srcptr + (linelen + padlen) * height; - - while(srcptr < endmem) - { - endline = srcptr + linelen; - - while(srcptr < endline) - { - temp = srcptr[0]; - *destptr++ = srcptr[2]; - *destptr++ = srcptr[1]; - *destptr++ = temp; - - srcptr += 3; - } - - // Skip the pad - srcptr += padlen; - } - - memcount = linelen * height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(allbuf + offset, memcount); - - ri.FS_WriteFile(fileName, buffer, memcount + 18); - - ri.Hunk_FreeTempMemory(allbuf); -} - -/* -================== -RB_TakeScreenshotJPEG -================== -*/ - -void RB_TakeScreenshotJPEG(int x, int y, int width, int height, char *fileName) -{ - byte *buffer; - size_t offset = 0, memcount; - int padlen; - - buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen); - memcount = (width * 3 + padlen) * height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(buffer + offset, memcount); - - RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, buffer + offset, padlen); - ri.Hunk_FreeTempMemory(buffer); -} - -/* -================== -RB_TakeScreenshotCmd -================== -*/ -const void *RB_TakeScreenshotCmd( const void *data ) { - const screenshotCommand_t *cmd; - - cmd = (const screenshotCommand_t *)data; - - if (cmd->jpeg) - RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); - else - RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); - - return (const void *)(cmd + 1); -} - -/* -================== -R_TakeScreenshot -================== -*/ -void R_TakeScreenshot( int x, int y, int width, int height, char *name, qboolean jpeg ) { - static char fileName[MAX_OSPATH]; // bad things if two screenshots per frame? - screenshotCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SCREENSHOT; - - cmd->x = x; - cmd->y = y; - cmd->width = width; - cmd->height = height; - Q_strncpyz( fileName, name, sizeof(fileName) ); - cmd->fileName = fileName; - cmd->jpeg = jpeg; -} - -/* -================== -R_ScreenshotFilename -================== -*/ -void R_ScreenshotFilename( int lastNumber, char *fileName ) { - int a,b,c,d; - - if ( lastNumber < 0 || lastNumber > 9999 ) { - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.tga" ); - return; - } - - a = lastNumber / 1000; - lastNumber -= a*1000; - b = lastNumber / 100; - lastNumber -= b*100; - c = lastNumber / 10; - lastNumber -= c*10; - d = lastNumber; - - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.tga" - , a, b, c, d ); -} - -/* -================== -R_ScreenshotFilename -================== -*/ -void R_ScreenshotFilenameJPEG( int lastNumber, char *fileName ) { - int a,b,c,d; - - if ( lastNumber < 0 || lastNumber > 9999 ) { - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.jpg" ); - return; - } - - a = lastNumber / 1000; - lastNumber -= a*1000; - b = lastNumber / 100; - lastNumber -= b*100; - c = lastNumber / 10; - lastNumber -= c*10; - d = lastNumber; - - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.jpg" - , a, b, c, d ); -} - -/* -==================== -R_LevelShot - -levelshots are specialized 128*128 thumbnails for -the menu system, sampled down from full screen distorted images -==================== -*/ -void R_LevelShot( void ) { - char checkname[MAX_OSPATH]; - byte *buffer; - byte *source, *allsource; - byte *src, *dst; - size_t offset = 0; - int padlen; - int x, y; - int r, g, b; - float xScale, yScale; - int xx, yy; - - Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName); - - allsource = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &padlen); - source = allsource + offset; - - buffer = ri.Hunk_AllocateTempMemory(128 * 128*3 + 18); - Com_Memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = 128; - buffer[14] = 128; - buffer[16] = 24; // pixel size - - // resample from source - xScale = glConfig.vidWidth / 512.0f; - yScale = glConfig.vidHeight / 384.0f; - for ( y = 0 ; y < 128 ; y++ ) { - for ( x = 0 ; x < 128 ; x++ ) { - r = g = b = 0; - for ( yy = 0 ; yy < 3 ; yy++ ) { - for ( xx = 0 ; xx < 4 ; xx++ ) { - src = source + (3 * glConfig.vidWidth + padlen) * (int)((y*3 + yy) * yScale) + - 3 * (int) ((x*4 + xx) * xScale); - r += src[0]; - g += src[1]; - b += src[2]; - } - } - dst = buffer + 18 + 3 * ( y * 128 + x ); - dst[0] = b / 12; - dst[1] = g / 12; - dst[2] = r / 12; - } - } - - // gamma correct - if ( glConfig.deviceSupportsGamma ) { - R_GammaCorrect( buffer + 18, 128 * 128 * 3 ); - } - - ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 ); - - ri.Hunk_FreeTempMemory(buffer); - ri.Hunk_FreeTempMemory(allsource); - - ri.Printf( PRINT_ALL, "Wrote %s\n", checkname ); -} - -/* -================== -R_ScreenShot_f - -screenshot -screenshot [silent] -screenshot [levelshot] -screenshot [filename] - -Doesn't print the pacifier message if there is a second arg -================== -*/ -void R_ScreenShot_f (void) { - char checkname[MAX_OSPATH]; - static int lastNumber = -1; - qboolean silent; - - if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) { - R_LevelShot(); - return; - } - - if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) { - silent = qtrue; - } else { - silent = qfalse; - } - - if ( ri.Cmd_Argc() == 2 && !silent ) { - // explicit filename - Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv( 1 ) ); - } else { - // scan for a free filename - - // if we have saved a previous screenshot, don't scan - // again, because recording demo avis can involve - // thousands of shots - if ( lastNumber == -1 ) { - lastNumber = 0; - } - // scan for a free number - for ( ; lastNumber <= 9999 ; lastNumber++ ) { - R_ScreenshotFilename( lastNumber, checkname ); - - if (!ri.FS_FileExists( checkname )) - { - break; // file doesn't exist - } - } - - if ( lastNumber >= 9999 ) { - ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n"); - return; - } - - lastNumber++; - } - - R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qfalse ); - - if ( !silent ) { - ri.Printf (PRINT_ALL, "Wrote %s\n", checkname); - } -} - -void R_ScreenShotJPEG_f (void) { - char checkname[MAX_OSPATH]; - static int lastNumber = -1; - qboolean silent; - - if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) { - R_LevelShot(); - return; - } - - if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) { - silent = qtrue; - } else { - silent = qfalse; - } - - if ( ri.Cmd_Argc() == 2 && !silent ) { - // explicit filename - Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.jpg", ri.Cmd_Argv( 1 ) ); - } else { - // scan for a free filename - - // if we have saved a previous screenshot, don't scan - // again, because recording demo avis can involve - // thousands of shots - if ( lastNumber == -1 ) { - lastNumber = 0; - } - // scan for a free number - for ( ; lastNumber <= 9999 ; lastNumber++ ) { - R_ScreenshotFilenameJPEG( lastNumber, checkname ); - - if (!ri.FS_FileExists( checkname )) - { - break; // file doesn't exist - } - } - - if ( lastNumber == 10000 ) { - ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n"); - return; - } - - lastNumber++; - } - - R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qtrue ); - - if ( !silent ) { - ri.Printf (PRINT_ALL, "Wrote %s\n", checkname); - } -} - -//============================================================================ - -/* -================== -RB_TakeVideoFrameCmd -================== -*/ -const void *RB_TakeVideoFrameCmd( const void *data ) -{ - const videoFrameCommand_t *cmd; - byte *cBuf; - size_t memcount, linelen; - int padwidth, avipadwidth, padlen, avipadlen; - GLint packAlign; - - cmd = (const videoFrameCommand_t *)data; - - qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); - - linelen = cmd->width * 3; - - // Alignment stuff for glReadPixels - padwidth = PAD(linelen, packAlign); - padlen = padwidth - linelen; - // AVI line padding - avipadwidth = PAD(linelen, AVI_LINE_PADDING); - avipadlen = avipadwidth - linelen; - - cBuf = PADP(cmd->captureBuffer, packAlign); - - qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB, - GL_UNSIGNED_BYTE, cBuf); - - memcount = padwidth * cmd->height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(cBuf, memcount); - - if(cmd->motionJpeg) - { - memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height, - r_aviMotionJpegQuality->integer, - cmd->width, cmd->height, cBuf, padlen); - ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount); - } - else - { - byte *lineend, *memend; - byte *srcptr, *destptr; - - srcptr = cBuf; - destptr = cmd->encodeBuffer; - memend = srcptr + memcount; - - // swap R and B and remove line paddings - while(srcptr < memend) - { - lineend = srcptr + linelen; - while(srcptr < lineend) - { - *destptr++ = srcptr[2]; - *destptr++ = srcptr[1]; - *destptr++ = srcptr[0]; - srcptr += 3; - } - - Com_Memset(destptr, '\0', avipadlen); - destptr += avipadlen; - - srcptr += padlen; - } - - ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, avipadwidth * cmd->height); - } - - return (const void *)(cmd + 1); -} - -//============================================================================ - -/* -** GL_SetDefaultState -*/ -void GL_SetDefaultState( void ) -{ - qglClearDepth( 1.0f ); - - qglCullFace(GL_FRONT); - - qglColor4f (1,1,1,1); - - // initialize downstream texture unit if we're running - // in a multitexture environment - if ( qglActiveTextureARB ) { - GL_SelectTexture( 1 ); - GL_TextureMode( r_textureMode->string ); - GL_TexEnv( GL_MODULATE ); - qglDisable( GL_TEXTURE_2D ); - GL_SelectTexture( 0 ); - } - - qglEnable(GL_TEXTURE_2D); - GL_TextureMode( r_textureMode->string ); - GL_TexEnv( GL_MODULATE ); - - qglShadeModel( GL_SMOOTH ); - qglDepthFunc( GL_LEQUAL ); - - // the vertex array is always enabled, but the color and texture - // arrays are enabled and disabled around the compiled vertex array call - qglEnableClientState (GL_VERTEX_ARRAY); - - // - // make sure our GL state vector is set correctly - // - glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE; - - qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - qglDepthMask( GL_TRUE ); - qglDisable( GL_DEPTH_TEST ); - qglEnable( GL_SCISSOR_TEST ); - qglDisable( GL_CULL_FACE ); - qglDisable( GL_BLEND ); -} - -/* -================ -R_PrintLongString - -Workaround for ri.Printf's 1024 characters buffer limit. -================ -*/ -void R_PrintLongString(const char *string) { - char buffer[1024]; - const char *p; - int size = strlen(string); - - p = string; - while(size > 0) - { - Q_strncpyz(buffer, p, sizeof (buffer) ); - ri.Printf( PRINT_ALL, "%s", buffer ); - p += 1023; - size -= 1023; - } -} - -/* -================ -GfxInfo_f -================ -*/ -void GfxInfo_f( void ) -{ - const char *enablestrings[] = - { - "disabled", - "enabled" - }; - const char *fsstrings[] = - { - "windowed", - "fullscreen" - }; - - ri.Printf( PRINT_ALL, "\nGL_VENDOR: %s\n", glConfig.vendor_string ); - ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string ); - ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string ); - ri.Printf( PRINT_ALL, "GL_EXTENSIONS: " ); - R_PrintLongString( glConfig.extensions_string ); - ri.Printf( PRINT_ALL, "\n" ); - ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize ); - ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.numTextureUnits ); - ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits ); - ri.Printf( PRINT_ALL, "MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] ); - if ( glConfig.displayFrequency ) - { - ri.Printf( PRINT_ALL, "%d\n", glConfig.displayFrequency ); - } - else - { - ri.Printf( PRINT_ALL, "N/A\n" ); - } - if ( glConfig.deviceSupportsGamma ) - { - ri.Printf( PRINT_ALL, "GAMMA: hardware w/ %d overbright bits\n", tr.overbrightBits ); - } - else - { - ri.Printf( PRINT_ALL, "GAMMA: software w/ %d overbright bits\n", tr.overbrightBits ); - } - - // rendering primitives - { - int primitives; - - // default is to use triangles if compiled vertex arrays are present - ri.Printf( PRINT_ALL, "rendering primitives: " ); - primitives = r_primitives->integer; - if ( primitives == 0 ) { - if ( qglLockArraysEXT ) { - primitives = 2; - } else { - primitives = 1; - } - } - if ( primitives == -1 ) { - ri.Printf( PRINT_ALL, "none\n" ); - } else if ( primitives == 2 ) { - ri.Printf( PRINT_ALL, "single glDrawElements\n" ); - } else if ( primitives == 1 ) { - ri.Printf( PRINT_ALL, "multiple glArrayElement\n" ); - } else if ( primitives == 3 ) { - ri.Printf( PRINT_ALL, "multiple glColor4ubv + glTexCoord2fv + glVertex3fv\n" ); - } - } - - ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string ); - ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer ); - ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer ); - ri.Printf( PRINT_ALL, "multitexture: %s\n", enablestrings[qglActiveTextureARB != 0] ); - ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] ); - ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] ); - ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] ); - if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) - { - ri.Printf( PRINT_ALL, "HACK: using vertex lightmap approximation\n" ); - } - if ( glConfig.hardwareType == GLHW_RAGEPRO ) - { - ri.Printf( PRINT_ALL, "HACK: ragePro approximations\n" ); - } - if ( glConfig.hardwareType == GLHW_RIVA128 ) - { - ri.Printf( PRINT_ALL, "HACK: riva128 approximations\n" ); - } - if ( r_finish->integer ) { - ri.Printf( PRINT_ALL, "Forcing glFinish\n" ); - } -} - -/* -=============== -R_Register -=============== -*/ -void R_Register( void ) -{ - #ifdef USE_RENDERER_DLOPEN - com_altivec = ri.Cvar_Get("com_altivec", "1", CVAR_ARCHIVE); - #endif - - // - // latched and archived variables - // - r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH); - - r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", - "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "2", CVAR_ARCHIVE | CVAR_LATCH ); - - r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH ); - ri.Cvar_CheckRange( r_picmip, 0, 16, qtrue ); - r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH ); - r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH ); - ri.Cvar_CheckRange( r_ext_multisample, 0, 4, qtrue ); - r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_mode = ri.Cvar_Get( "r_mode", "3", CVAR_ARCHIVE | CVAR_LATCH ); - r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE ); - r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH ); - r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH ); - r_customPixelAspect = ri.Cvar_Get( "r_customPixelAspect", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_simpleMipMaps = ri.Cvar_Get( "r_simpleMipMaps", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0); - r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH); - r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_ignoreFastPath = ri.Cvar_Get( "r_ignoreFastPath", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH); - ri.Cvar_CheckRange(r_greyscale, 0, 1, qfalse); - - // - // temporary latched variables that can only change over a restart - // - r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT ); - r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH ); - r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH ); - r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH ); - - // - // archived variables that can change at any time - // - r_lodCurveError = ri.Cvar_Get( "r_lodCurveError", "250", CVAR_ARCHIVE|CVAR_CHEAT ); - r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE ); - r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE ); - r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT ); - ri.Cvar_CheckRange( r_znear, 0.001f, 200, qfalse ); - r_zproj = ri.Cvar_Get( "r_zproj", "64", CVAR_ARCHIVE ); - r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", CVAR_ARCHIVE ); - r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE ); - r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE ); - r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE ); - r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE ); - r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE ); - r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE ); - r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE); - r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE ); - r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0", - CVAR_ARCHIVE | CVAR_LATCH ); - r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE ); - r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE ); - - r_railWidth = ri.Cvar_Get( "r_railWidth", "16", CVAR_ARCHIVE ); - r_railCoreWidth = ri.Cvar_Get( "r_railCoreWidth", "6", CVAR_ARCHIVE ); - r_railSegmentLength = ri.Cvar_Get( "r_railSegmentLength", "32", CVAR_ARCHIVE ); - - r_primitives = ri.Cvar_Get( "r_primitives", "0", CVAR_ARCHIVE ); - - r_ambientScale = ri.Cvar_Get( "r_ambientScale", "0.6", CVAR_CHEAT ); - r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT ); - - r_anaglyphMode = ri.Cvar_Get("r_anaglyphMode", "0", CVAR_ARCHIVE); - - // - // temporary variables that can change at any time - // - r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_TEMP ); - - r_debugLight = ri.Cvar_Get( "r_debuglight", "0", CVAR_TEMP ); - r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT ); - r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 ); - r_saveFontData = ri.Cvar_Get( "r_saveFontData", "0", 0 ); - - r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT ); - r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT ); - r_lightmap = ri.Cvar_Get ("r_lightmap", "0", 0 ); - r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_CHEAT ); - - r_flareSize = ri.Cvar_Get ("r_flareSize", "40", CVAR_CHEAT); - r_flareFade = ri.Cvar_Get ("r_flareFade", "7", CVAR_CHEAT); - r_flareCoeff = ri.Cvar_Get ("r_flareCoeff", FLARE_STDCOEFF, CVAR_CHEAT); - - r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT); - - r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); - r_lodscale = ri.Cvar_Get( "r_lodscale", "5", CVAR_CHEAT ); - r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT); - r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT ); - r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT ); - r_nocull = ri.Cvar_Get ("r_nocull", "0", CVAR_CHEAT); - r_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT); - r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT); - r_speeds = ri.Cvar_Get ("r_speeds", "0", CVAR_CHEAT); - r_verbose = ri.Cvar_Get( "r_verbose", "0", CVAR_CHEAT ); - r_logFile = ri.Cvar_Get( "r_logFile", "0", CVAR_CHEAT ); - r_debugSurface = ri.Cvar_Get ("r_debugSurface", "0", CVAR_CHEAT); - r_nobind = ri.Cvar_Get ("r_nobind", "0", CVAR_CHEAT); - r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT); - r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT); - r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT); - r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT); - r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT ); - r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT ); - r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT ); - r_lockpvs = ri.Cvar_Get ("r_lockpvs", "0", CVAR_CHEAT); - r_noportals = ri.Cvar_Get ("r_noportals", "0", CVAR_CHEAT); - r_shadows = ri.Cvar_Get( "cg_shadows", "1", 0 ); - - r_marksOnTriangleMeshes = ri.Cvar_Get("r_marksOnTriangleMeshes", "0", CVAR_ARCHIVE); - - r_aviMotionJpegQuality = ri.Cvar_Get("r_aviMotionJpegQuality", "90", CVAR_ARCHIVE); - r_screenshotJpegQuality = ri.Cvar_Get("r_screenshotJpegQuality", "90", CVAR_ARCHIVE); - - r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0); - r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0); - - // make sure all the commands added here are also - // removed in R_Shutdown - ri.Cmd_AddCommand( "imagelist", R_ImageList_f ); - ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f ); - ri.Cmd_AddCommand( "skinlist", R_SkinList_f ); - ri.Cmd_AddCommand( "modellist", R_Modellist_f ); - ri.Cmd_AddCommand( "modelist", R_ModeList_f ); - ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f ); - ri.Cmd_AddCommand( "screenshotJPEG", R_ScreenShotJPEG_f ); - ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f ); - ri.Cmd_AddCommand( "minimize", GLimp_Minimize ); -} - -/* -=============== -R_Init -=============== -*/ -void R_Init( void ) { - int err; - int i; - byte *ptr; - - ri.Printf( PRINT_ALL, "----- R_Init -----\n" ); - - // clear all our internal state - Com_Memset( &tr, 0, sizeof( tr ) ); - Com_Memset( &backEnd, 0, sizeof( backEnd ) ); - Com_Memset( &tess, 0, sizeof( tess ) ); - - if(sizeof(glconfig_t) != 11332) - ri.Error( ERR_FATAL, "Mod ABI incompatible: sizeof(glconfig_t) == %u != 11332", (unsigned int) sizeof(glconfig_t)); - -// Swap_Init(); - - if ( (intptr_t)tess.xyz & 15 ) { - ri.Printf( PRINT_WARNING, "tess.xyz not 16 byte aligned\n" ); - } - Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) ); - - // - // init function tables - // - for ( i = 0; i < FUNCTABLE_SIZE; i++ ) - { - tr.sinTable[i] = sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) ); - tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f; - tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE; - tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i]; - - if ( i < FUNCTABLE_SIZE / 2 ) - { - if ( i < FUNCTABLE_SIZE / 4 ) - { - tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 ); - } - else - { - tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4]; - } - } - else - { - tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2]; - } - } - - R_InitFogTable(); - - R_NoiseInit(); - - R_Register(); - - max_polys = r_maxpolys->integer; - if (max_polys < MAX_POLYS) - max_polys = MAX_POLYS; - - max_polyverts = r_maxpolyverts->integer; - if (max_polyverts < MAX_POLYVERTS) - max_polyverts = MAX_POLYVERTS; - - ptr = ri.Hunk_Alloc( sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); - backEndData = (backEndData_t *) ptr; - backEndData->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData )); - backEndData->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys); - R_InitNextFrame(); - - InitOpenGL(); - - R_InitImages(); - - R_InitShaders(); - - R_InitSkins(); - - R_ModelInit(); - - R_InitFreeType(); - - - err = qglGetError(); - if ( err != GL_NO_ERROR ) - ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err); - - // print info - GfxInfo_f(); - ri.Printf( PRINT_ALL, "----- finished R_Init -----\n" ); -} - -/* -=============== -RE_Shutdown -=============== -*/ -void RE_Shutdown( qboolean destroyWindow ) { - - ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow ); - - ri.Cmd_RemoveCommand ("modellist"); - ri.Cmd_RemoveCommand ("screenshotJPEG"); - ri.Cmd_RemoveCommand ("screenshot"); - ri.Cmd_RemoveCommand ("imagelist"); - ri.Cmd_RemoveCommand ("shaderlist"); - ri.Cmd_RemoveCommand ("skinlist"); - ri.Cmd_RemoveCommand ("gfxinfo"); - ri.Cmd_RemoveCommand("minimize"); - ri.Cmd_RemoveCommand( "modelist" ); - ri.Cmd_RemoveCommand( "shaderstate" ); - - - if ( tr.registered ) { - R_IssuePendingRenderCommands(); - R_DeleteTextures(); - } - - R_DoneFreeType(); - - // shut down platform specific OpenGL stuff - if ( destroyWindow ) { - GLimp_Shutdown(); - - Com_Memset( &glConfig, 0, sizeof( glConfig ) ); - Com_Memset( &glState, 0, sizeof( glState ) ); - } - - tr.registered = qfalse; -} - - -/* -============= -RE_EndRegistration - -Touch all images to make sure they are resident -============= -*/ -void RE_EndRegistration( void ) { - R_IssuePendingRenderCommands(); - if (!ri.Sys_LowPhysicalMemory()) { - RB_ShowImages(); - } -} - - -/* -@@@@@@@@@@@@@@@@@@@@@ -GetRefAPI - -@@@@@@@@@@@@@@@@@@@@@ -*/ -#ifdef USE_RENDERER_DLOPEN -Q_EXPORT refexport_t* QDECL GetRefAPI ( int apiVersion, refimport_t *rimp ) { -#else -refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { -#endif - - static refexport_t re; - - ri = *rimp; - - Com_Memset( &re, 0, sizeof( re ) ); - - if ( apiVersion != REF_API_VERSION ) { - ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n", - REF_API_VERSION, apiVersion ); - return NULL; - } - - // the RE_ functions are Renderer Entry points - - re.Shutdown = RE_Shutdown; - - re.BeginRegistration = RE_BeginRegistration; - re.RegisterModel = RE_RegisterModel; - re.RegisterSkin = RE_RegisterSkin; - re.RegisterShader = RE_RegisterShader; - re.RegisterShaderNoMip = RE_RegisterShaderNoMip; - re.LoadWorld = RE_LoadWorldMap; - re.SetWorldVisData = RE_SetWorldVisData; - re.EndRegistration = RE_EndRegistration; - - re.BeginFrame = RE_BeginFrame; - re.EndFrame = RE_EndFrame; - - re.MarkFragments = R_MarkFragments; - re.LerpTag = R_LerpTag; - re.ModelBounds = R_ModelBounds; - - re.ClearScene = RE_ClearScene; - re.AddRefEntityToScene = RE_AddRefEntityToScene; - re.AddPolyToScene = RE_AddPolyToScene; - re.LFX_ParticleEffect = NULL; - re.LightForPoint = R_LightForPoint; - re.AddLightToScene = RE_AddLightToScene; - re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene; - re.RenderScene = RE_RenderScene; - - re.SetColor = RE_SetColor; - re.DrawStretchPic = RE_StretchPic; - re.DrawStretchRaw = RE_StretchRaw; - re.UploadCinematic = RE_UploadCinematic; - - re.RegisterFont = RE_RegisterFont; - re.RemapShader = R_RemapShader; - re.GetEntityToken = R_GetEntityToken; - re.inPVS = R_inPVS; - - re.TakeVideoFrame = RE_TakeVideoFrame; - - return &re; -} diff --git a/code/renderergl1/tr_light.c b/code/renderergl1/tr_light.c deleted file mode 100644 index fc6af6a917..0000000000 --- a/code/renderergl1/tr_light.c +++ /dev/null @@ -1,394 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_light.c - -#include "tr_local.h" - -#define DLIGHT_AT_RADIUS 16 -// at the edge of a dlight's influence, this amount of light will be added - -#define DLIGHT_MINIMUM_RADIUS 16 -// never calculate a range less than this to prevent huge light numbers - - -/* -=============== -R_TransformDlights - -Transforms the origins of an array of dlights. -Used by both the front end (for DlightBmodel) and -the back end (before doing the lighting calculation) -=============== -*/ -void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) { - int i; - vec3_t temp; - - for ( i = 0 ; i < count ; i++, dl++ ) { - VectorSubtract( dl->origin, or->origin, temp ); - dl->transformed[0] = DotProduct( temp, or->axis[0] ); - dl->transformed[1] = DotProduct( temp, or->axis[1] ); - dl->transformed[2] = DotProduct( temp, or->axis[2] ); - } -} - -/* -============= -R_DlightBmodel - -Determine which dynamic lights may effect this bmodel -============= -*/ -void R_DlightBmodel( bmodel_t *bmodel ) { - int i, j; - dlight_t *dl; - int mask; - msurface_t *surf; - - // transform all the lights - R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or ); - - mask = 0; - for ( i=0 ; itransformed[j] - bmodel->bounds[1][j] > dl->radius ) { - break; - } - if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) { - break; - } - } - if ( j < 3 ) { - continue; - } - - // we need to check this light - mask |= 1 << i; - } - - tr.currentEntity->needDlights = (mask != 0); - - // set the dlight bits in all the surfaces - for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) { - surf = bmodel->firstSurface + i; - - if ( *surf->data == SF_FACE ) { - ((srfSurfaceFace_t *)surf->data)->dlightBits = mask; - } else if ( *surf->data == SF_GRID ) { - ((srfGridMesh_t *)surf->data)->dlightBits = mask; - } else if ( *surf->data == SF_TRIANGLES ) { - ((srfTriangles_t *)surf->data)->dlightBits = mask; - } - } -} - - -/* -============================================================================= - -LIGHT SAMPLING - -============================================================================= -*/ - -extern cvar_t *r_ambientScale; -extern cvar_t *r_directedScale; -extern cvar_t *r_debugLight; - -/* -================= -R_SetupEntityLightingGrid - -================= -*/ -static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) { - vec3_t lightOrigin; - int pos[3]; - int i, j; - byte *gridData; - float frac[3]; - int gridStep[3]; - vec3_t direction; - float totalFactor; - - if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is - // sinking into the ground can still be lit, and so - // multi-part models can be lit identically - VectorCopy( ent->e.lightingOrigin, lightOrigin ); - } else { - VectorCopy( ent->e.origin, lightOrigin ); - } - - VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin ); - for ( i = 0 ; i < 3 ; i++ ) { - float v; - - v = lightOrigin[i]*tr.world->lightGridInverseSize[i]; - pos[i] = floor( v ); - frac[i] = v - pos[i]; - if ( pos[i] < 0 ) { - pos[i] = 0; - } else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) { - pos[i] = tr.world->lightGridBounds[i] - 1; - } - } - - VectorClear( ent->ambientLight ); - VectorClear( ent->directedLight ); - VectorClear( direction ); - - assert( tr.world->lightGridData ); // NULL with -nolight maps - - // trilerp the light value - gridStep[0] = 8; - gridStep[1] = 8 * tr.world->lightGridBounds[0]; - gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1]; - gridData = tr.world->lightGridData + pos[0] * gridStep[0] - + pos[1] * gridStep[1] + pos[2] * gridStep[2]; - - totalFactor = 0; - for ( i = 0 ; i < 8 ; i++ ) { - float factor; - byte *data; - int lat, lng; - vec3_t normal; - #if idppc - float d0, d1, d2, d3, d4, d5; - #endif - factor = 1.0; - data = gridData; - for ( j = 0 ; j < 3 ; j++ ) { - if ( i & (1<ambientLight[0] += factor * d0; - ent->ambientLight[1] += factor * d1; - ent->ambientLight[2] += factor * d2; - - ent->directedLight[0] += factor * d3; - ent->directedLight[1] += factor * d4; - ent->directedLight[2] += factor * d5; - #else - ent->ambientLight[0] += factor * data[0]; - ent->ambientLight[1] += factor * data[1]; - ent->ambientLight[2] += factor * data[2]; - - ent->directedLight[0] += factor * data[3]; - ent->directedLight[1] += factor * data[4]; - ent->directedLight[2] += factor * data[5]; - #endif - lat = data[7]; - lng = data[6]; - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - VectorMA( direction, factor, normal, direction ); - } - - if ( totalFactor > 0 && totalFactor < 0.99 ) { - totalFactor = 1.0f / totalFactor; - VectorScale( ent->ambientLight, totalFactor, ent->ambientLight ); - VectorScale( ent->directedLight, totalFactor, ent->directedLight ); - } - - VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight ); - VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight ); - - VectorNormalize2( direction, ent->lightDir ); -} - - -/* -=============== -LogLight -=============== -*/ -static void LogLight( trRefEntity_t *ent ) { - int max1, max2; - - if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) { - return; - } - - max1 = ent->ambientLight[0]; - if ( ent->ambientLight[1] > max1 ) { - max1 = ent->ambientLight[1]; - } else if ( ent->ambientLight[2] > max1 ) { - max1 = ent->ambientLight[2]; - } - - max2 = ent->directedLight[0]; - if ( ent->directedLight[1] > max2 ) { - max2 = ent->directedLight[1]; - } else if ( ent->directedLight[2] > max2 ) { - max2 = ent->directedLight[2]; - } - - ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 ); -} - -/* -================= -R_SetupEntityLighting - -Calculates all the lighting values that will be used -by the Calc_* functions -================= -*/ -void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { - int i; - dlight_t *dl; - float power; - vec3_t dir; - float d; - vec3_t lightDir; - vec3_t lightOrigin; - - // lighting calculations - if ( ent->lightingCalculated ) { - return; - } - ent->lightingCalculated = qtrue; - - // - // trace a sample point down to find ambient light - // - if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is - // sinking into the ground can still be lit, and so - // multi-part models can be lit identically - VectorCopy( ent->e.lightingOrigin, lightOrigin ); - } else { - VectorCopy( ent->e.origin, lightOrigin ); - } - - // if NOWORLDMODEL, only use dynamic lights (menu system, etc) - if ( !(refdef->rdflags & RDF_NOWORLDMODEL ) - && tr.world->lightGridData ) { - R_SetupEntityLightingGrid( ent ); - } else { - ent->ambientLight[0] = ent->ambientLight[1] = - ent->ambientLight[2] = tr.identityLight * 150; - ent->directedLight[0] = ent->directedLight[1] = - ent->directedLight[2] = tr.identityLight * 150; - VectorCopy( tr.sunDirection, ent->lightDir ); - } - - // bonus items and view weapons have a fixed minimum add - if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) { - // give everything a minimum light add - ent->ambientLight[0] += tr.identityLight * 32; - ent->ambientLight[1] += tr.identityLight * 32; - ent->ambientLight[2] += tr.identityLight * 32; - } - - // - // modify the light by dynamic lights - // - d = VectorLength( ent->directedLight ); - VectorScale( ent->lightDir, d, lightDir ); - - for ( i = 0 ; i < refdef->num_dlights ; i++ ) { - dl = &refdef->dlights[i]; - VectorSubtract( dl->origin, lightOrigin, dir ); - d = VectorNormalize( dir ); - - power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius ); - if ( d < DLIGHT_MINIMUM_RADIUS ) { - d = DLIGHT_MINIMUM_RADIUS; - } - d = power / ( d * d ); - - VectorMA( ent->directedLight, d, dl->color, ent->directedLight ); - VectorMA( lightDir, d, dir, lightDir ); - } - - // clamp ambient - for ( i = 0 ; i < 3 ; i++ ) { - if ( ent->ambientLight[i] > tr.identityLightByte ) { - ent->ambientLight[i] = tr.identityLightByte; - } - } - - if ( r_debugLight->integer ) { - LogLight( ent ); - } - - // save out the byte packet version - ((byte *)&ent->ambientLightInt)[0] = ri.ftol(ent->ambientLight[0]); - ((byte *)&ent->ambientLightInt)[1] = ri.ftol(ent->ambientLight[1]); - ((byte *)&ent->ambientLightInt)[2] = ri.ftol(ent->ambientLight[2]); - ((byte *)&ent->ambientLightInt)[3] = 0xff; - - // transform the direction to local space - VectorNormalize( lightDir ); - ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] ); - ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] ); - ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] ); -} - -/* -================= -R_LightForPoint -================= -*/ -int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) -{ - trRefEntity_t ent; - - if ( tr.world->lightGridData == NULL ) - return qfalse; - - Com_Memset(&ent, 0, sizeof(ent)); - VectorCopy( point, ent.e.origin ); - R_SetupEntityLightingGrid( &ent ); - VectorCopy(ent.ambientLight, ambientLight); - VectorCopy(ent.directedLight, directedLight); - VectorCopy(ent.lightDir, lightDir); - - return qtrue; -} diff --git a/code/renderergl1/tr_local.h b/code/renderergl1/tr_local.h deleted file mode 100644 index 66c13d4514..0000000000 --- a/code/renderergl1/tr_local.h +++ /dev/null @@ -1,1600 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - - -#ifndef TR_LOCAL_H -#define TR_LOCAL_H - -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "../renderercommon/tr_public.h" -#include "../renderercommon/tr_common.h" -#include "../renderercommon/iqm.h" -#include "../renderercommon/qgl.h" - -#define GL_INDEX_TYPE GL_UNSIGNED_INT -typedef unsigned int glIndex_t; - -// 14 bits -// can't be increased without changing bit packing for drawsurfs -// see QSORT_SHADERNUM_SHIFT -#define SHADERNUM_BITS 14 -#define MAX_SHADERS (1<or.origin in local coordinates - float modelMatrix[16]; -} orientationr_t; - -//=============================================================================== - -typedef enum { - SS_BAD, - SS_PORTAL, // mirrors, portals, viewscreens - SS_ENVIRONMENT, // sky box - SS_OPAQUE, // opaque - - SS_DECAL, // scorch marks, etc. - SS_SEE_THROUGH, // ladders, grates, grills that may have small blended edges - // in addition to alpha test - SS_BANNER, - - SS_FOG, - - SS_UNDERWATER, // for items that should be drawn in front of the water plane - - SS_BLEND0, // regular transparency and filters - SS_BLEND1, // generally only used for additive type effects - SS_BLEND2, - SS_BLEND3, - - SS_BLEND6, - SS_STENCIL_SHADOW, - SS_ALMOST_NEAREST, // gun smoke puffs - - SS_NEAREST // blood blobs -} shaderSort_t; - - -#define MAX_SHADER_STAGES 8 - -typedef enum { - GF_NONE, - - GF_SIN, - GF_SQUARE, - GF_TRIANGLE, - GF_SAWTOOTH, - GF_INVERSE_SAWTOOTH, - - GF_NOISE - -} genFunc_t; - - -typedef enum { - DEFORM_NONE, - DEFORM_WAVE, - DEFORM_NORMALS, - DEFORM_BULGE, - DEFORM_MOVE, - DEFORM_PROJECTION_SHADOW, - DEFORM_AUTOSPRITE, - DEFORM_AUTOSPRITE2, - DEFORM_TEXT0, - DEFORM_TEXT1, - DEFORM_TEXT2, - DEFORM_TEXT3, - DEFORM_TEXT4, - DEFORM_TEXT5, - DEFORM_TEXT6, - DEFORM_TEXT7 -} deform_t; - -typedef enum { - AGEN_IDENTITY, - AGEN_SKIP, - AGEN_ENTITY, - AGEN_ONE_MINUS_ENTITY, - AGEN_VERTEX, - AGEN_ONE_MINUS_VERTEX, - AGEN_LIGHTING_SPECULAR, - AGEN_WAVEFORM, - AGEN_PORTAL, - AGEN_CONST -} alphaGen_t; - -typedef enum { - CGEN_BAD, - CGEN_IDENTITY_LIGHTING, // tr.identityLight - CGEN_IDENTITY, // always (1,1,1,1) - CGEN_ENTITY, // grabbed from entity's modulate field - CGEN_ONE_MINUS_ENTITY, // grabbed from 1 - entity.modulate - CGEN_EXACT_VERTEX, // tess.vertexColors - CGEN_VERTEX, // tess.vertexColors * tr.identityLight - CGEN_ONE_MINUS_VERTEX, - CGEN_WAVEFORM, // programmatically generated - CGEN_LIGHTING_DIFFUSE, - CGEN_FOG, // standard fog - CGEN_CONST // fixed color -} colorGen_t; - -typedef enum { - TCGEN_BAD, - TCGEN_IDENTITY, // clear to 0,0 - TCGEN_LIGHTMAP, - TCGEN_TEXTURE, - TCGEN_ENVIRONMENT_MAPPED, - TCGEN_FOG, - TCGEN_VECTOR // S and T from world coordinates -} texCoordGen_t; - -typedef enum { - ACFF_NONE, - ACFF_MODULATE_RGB, - ACFF_MODULATE_RGBA, - ACFF_MODULATE_ALPHA -} acff_t; - -typedef struct { - genFunc_t func; - - float base; - float amplitude; - float phase; - float frequency; -} waveForm_t; - -#define TR_MAX_TEXMODS 4 - -typedef enum { - TMOD_NONE, - TMOD_TRANSFORM, - TMOD_TURBULENT, - TMOD_SCROLL, - TMOD_SCALE, - TMOD_STRETCH, - TMOD_ROTATE, - TMOD_ENTITY_TRANSLATE -} texMod_t; - -#define MAX_SHADER_DEFORMS 3 -typedef struct { - deform_t deformation; // vertex coordinate modification type - - vec3_t moveVector; - waveForm_t deformationWave; - float deformationSpread; - - float bulgeWidth; - float bulgeHeight; - float bulgeSpeed; -} deformStage_t; - - -typedef struct { - texMod_t type; - - // used for TMOD_TURBULENT and TMOD_STRETCH - waveForm_t wave; - - // used for TMOD_TRANSFORM - float matrix[2][2]; // s' = s * m[0][0] + t * m[1][0] + trans[0] - float translate[2]; // t' = s * m[0][1] + t * m[0][1] + trans[1] - - // used for TMOD_SCALE - float scale[2]; // s *= scale[0] - // t *= scale[1] - - // used for TMOD_SCROLL - float scroll[2]; // s' = s + scroll[0] * time - // t' = t + scroll[1] * time - - // + = clockwise - // - = counterclockwise - float rotateSpeed; - -} texModInfo_t; - - -#define MAX_IMAGE_ANIMATIONS 8 - -typedef struct { - image_t *image[MAX_IMAGE_ANIMATIONS]; - int numImageAnimations; - float imageAnimationSpeed; - - texCoordGen_t tcGen; - vec3_t tcGenVectors[2]; - - int numTexMods; - texModInfo_t *texMods; - - int videoMapHandle; - qboolean isLightmap; - qboolean isVideoMap; -} textureBundle_t; - -#define NUM_TEXTURE_BUNDLES 2 - -typedef struct { - qboolean active; - - textureBundle_t bundle[NUM_TEXTURE_BUNDLES]; - - waveForm_t rgbWave; - colorGen_t rgbGen; - - waveForm_t alphaWave; - alphaGen_t alphaGen; - - byte constantColor[4]; // for CGEN_CONST and AGEN_CONST - - unsigned stateBits; // GLS_xxxx mask - - acff_t adjustColorsForFog; - - qboolean isDetail; -} shaderStage_t; - -struct shaderCommands_s; - -typedef enum { - CT_FRONT_SIDED, - CT_BACK_SIDED, - CT_TWO_SIDED -} cullType_t; - -typedef enum { - FP_NONE, // surface is translucent and will just be adjusted properly - FP_EQUAL, // surface is opaque but possibly alpha tested - FP_LE // surface is trnaslucent, but still needs a fog pass (fog surface) -} fogPass_t; - -typedef struct { - float cloudHeight; - image_t *outerbox[6], *innerbox[6]; -} skyParms_t; - -typedef struct { - vec3_t color; - float depthForOpaque; -} fogParms_t; - - -typedef struct shader_s { - char name[MAX_QPATH]; // game path, including extension - int lightmapIndex; // for a shader to match, both name and lightmapIndex must match - - int index; // this shader == tr.shaders[index] - int sortedIndex; // this shader == tr.sortedShaders[sortedIndex] - - float sort; // lower numbered shaders draw before higher numbered - - qboolean defaultShader; // we want to return index 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - - qboolean explicitlyDefined; // found in a .shader file - - int surfaceFlags; // if explicitlyDefined, this will have SURF_* flags - int contentFlags; - - qboolean entityMergable; // merge across entites optimizable (smoke, blood) - - qboolean isSky; - skyParms_t sky; - fogParms_t fogParms; - - float portalRange; // distance to fog out at - - int multitextureEnv; // 0, GL_MODULATE, GL_ADD (FIXME: put in stage) - - cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED - qboolean polygonOffset; // set for decals and other items that must be offset - qboolean noMipMaps; // for console fonts, 2D elements, etc. - qboolean noPicMip; // for images that must always be full resolution - - fogPass_t fogPass; // draw a blended pass, possibly with depth test equals - - qboolean needsNormal; // not all shaders will need all data to be gathered - qboolean needsST1; - qboolean needsST2; - qboolean needsColor; - - int numDeforms; - deformStage_t deforms[MAX_SHADER_DEFORMS]; - - int numUnfoggedPasses; - shaderStage_t *stages[MAX_SHADER_STAGES]; - - void (*optimalStageIteratorFunc)( void ); - - float clampTime; // time this shader is clamped to - float timeOffset; // current time offset for this shader - - struct shader_s *remappedShader; // current shader this one is remapped too - - struct shader_s *next; -} shader_t; - - -// trRefdef_t holds everything that comes in refdef_t, -// as well as the locally generated scene information -typedef struct { - int x, y, width, height; - float fov_x, fov_y; - vec3_t vieworg; - vec3_t viewaxis[3]; // transformation matrix - - stereoFrame_t stereoFrame; - - int time; // time in milliseconds for shader effects and other time dependent rendering issues - int rdflags; // RDF_NOWORLDMODEL, etc - - // 1 bits will prevent the associated area from rendering at all - byte areamask[MAX_MAP_AREA_BYTES]; - qboolean areamaskModified; // qtrue if areamask changed since last scene - - float floatTime; // tr.refdef.time / 1000.0 - - // text messages for deform text shaders - char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; - - int num_entities; - trRefEntity_t *entities; - - int num_dlights; - struct dlight_s *dlights; - - int numPolys; - struct srfPoly_s *polys; - - int numDrawSurfs; - struct drawSurf_s *drawSurfs; - - -} trRefdef_t; - - -//================================================================================= - -// skins allow models to be retextured without modifying the model file -typedef struct { - char name[MAX_QPATH]; - shader_t *shader; -} skinSurface_t; - -typedef struct skin_s { - char name[MAX_QPATH]; // game path, including extension - int numSurfaces; - skinSurface_t *surfaces[MD3_MAX_SURFACES]; -} skin_t; - - -typedef struct { - int originalBrushNumber; - vec3_t bounds[2]; - - unsigned colorInt; // in packed byte format - float tcScale; // texture coordinate vector scales - fogParms_t parms; - - // for clipping distance in fog when outside - qboolean hasSurface; - float surface[4]; -} fog_t; - -typedef struct { - orientationr_t or; - orientationr_t world; - vec3_t pvsOrigin; // may be different than or.origin for portals - qboolean isPortal; // true if this view is through a portal - qboolean isMirror; // the portal is a mirror, invert the face culling - int frameSceneNum; // copied from tr.frameSceneNum - int frameCount; // copied from tr.frameCount - cplane_t portalPlane; // clip anything behind this if mirroring - int viewportX, viewportY, viewportWidth, viewportHeight; - float fovX, fovY; - float projectionMatrix[16]; - cplane_t frustum[4]; - vec3_t visBounds[2]; - float zFar; - stereoFrame_t stereoFrame; -} viewParms_t; - - -/* -============================================================================== - -SURFACES - -============================================================================== -*/ - -// any changes in surfaceType must be mirrored in rb_surfaceTable[] -typedef enum { - SF_BAD, - SF_SKIP, // ignore - SF_FACE, - SF_GRID, - SF_TRIANGLES, - SF_POLY, - SF_MD3, - SF_MDR, - SF_IQM, - SF_FLARE, - SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity - SF_DISPLAY_LIST, - - SF_NUM_SURFACE_TYPES, - SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int ) -} surfaceType_t; - -typedef struct drawSurf_s { - unsigned sort; // bit combination for fast compares - surfaceType_t *surface; // any of surface*_t -} drawSurf_t; - -#define MAX_FACE_POINTS 64 - -#define MAX_PATCH_SIZE 32 // max dimensions of a patch mesh in map file -#define MAX_GRID_SIZE 65 // max dimensions of a grid mesh in memory - -// when cgame directly specifies a polygon, it becomes a srfPoly_t -// as soon as it is called -typedef struct srfPoly_s { - surfaceType_t surfaceType; - qhandle_t hShader; - int fogIndex; - int numVerts; - polyVert_t *verts; -} srfPoly_t; - -typedef struct srfDisplayList_s { - surfaceType_t surfaceType; - int listNum; -} srfDisplayList_t; - - -typedef struct srfFlare_s { - surfaceType_t surfaceType; - vec3_t origin; - vec3_t normal; - vec3_t color; -} srfFlare_t; - -typedef struct srfGridMesh_s { - surfaceType_t surfaceType; - - // dynamic lighting information - int dlightBits; - - // culling information - vec3_t meshBounds[2]; - vec3_t localOrigin; - float meshRadius; - - // lod information, which may be different - // than the culling information to allow for - // groups of curves that LOD as a unit - vec3_t lodOrigin; - float lodRadius; - int lodFixed; - int lodStitched; - - // vertexes - int width, height; - float *widthLodError; - float *heightLodError; - drawVert_t verts[1]; // variable sized -} srfGridMesh_t; - - - -#define VERTEXSIZE 8 -typedef struct { - surfaceType_t surfaceType; - cplane_t plane; - - // dynamic lighting information - int dlightBits; - - // triangle definitions (no normals at points) - int numPoints; - int numIndices; - int ofsIndices; - float points[1][VERTEXSIZE]; // variable sized - // there is a variable length list of indices here also -} srfSurfaceFace_t; - - -// misc_models in maps are turned into direct geometry by q3map -typedef struct { - surfaceType_t surfaceType; - - // dynamic lighting information - int dlightBits; - - // culling information (FIXME: use this!) - vec3_t bounds[2]; - vec3_t localOrigin; - float radius; - - // triangle definitions - int numIndexes; - int *indexes; - - int numVerts; - drawVert_t *verts; -} srfTriangles_t; - -// inter-quake-model -typedef struct { - int num_vertexes; - int num_triangles; - int num_frames; - int num_surfaces; - int num_joints; - int num_poses; - struct srfIQModel_s *surfaces; - - float *positions; - float *texcoords; - float *normals; - float *tangents; - byte *blendIndexes; - union { - float *f; - byte *b; - } blendWeights; - byte *colors; - int *triangles; - - // depending upon the exporter, blend indices and weights might be int/float - // as opposed to the recommended byte/byte, for example Noesis exports - // int/float whereas the official IQM tool exports byte/byte - byte blendWeightsType; // IQM_UBYTE or IQM_FLOAT - - int *jointParents; - float *jointMats; - float *poseMats; - float *bounds; - char *names; -} iqmData_t; - -// inter-quake-model surface -typedef struct srfIQModel_s { - surfaceType_t surfaceType; - char name[MAX_QPATH]; - shader_t *shader; - iqmData_t *data; - int first_vertex, num_vertexes; - int first_triangle, num_triangles; -} srfIQModel_t; - - -extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *); - -/* -============================================================================== - -BRUSH MODELS - -============================================================================== -*/ - - -// -// in memory representation -// - -#define SIDE_FRONT 0 -#define SIDE_BACK 1 -#define SIDE_ON 2 - -typedef struct msurface_s { - int viewCount; // if == tr.viewCount, already added - struct shader_s *shader; - int fogIndex; - - surfaceType_t *data; // any of srf*_t -} msurface_t; - - - -#define CONTENTS_NODE -1 -typedef struct mnode_s { - // common with leaf and node - int contents; // -1 for nodes, to differentiate from leafs - int visframe; // node needs to be traversed if current - vec3_t mins, maxs; // for bounding box culling - struct mnode_s *parent; - - // node specific - cplane_t *plane; - struct mnode_s *children[2]; - - // leaf specific - int cluster; - int area; - - msurface_t **firstmarksurface; - int nummarksurfaces; -} mnode_t; - -typedef struct { - vec3_t bounds[2]; // for culling - msurface_t *firstSurface; - int numSurfaces; -} bmodel_t; - -typedef struct { - char name[MAX_QPATH]; // ie: maps/tim_dm2.bsp - char baseName[MAX_QPATH]; // ie: tim_dm2 - - int dataSize; - - int numShaders; - dshader_t *shaders; - - bmodel_t *bmodels; - - int numplanes; - cplane_t *planes; - - int numnodes; // includes leafs - int numDecisionNodes; - mnode_t *nodes; - - int numsurfaces; - msurface_t *surfaces; - - int nummarksurfaces; - msurface_t **marksurfaces; - - int numfogs; - fog_t *fogs; - - vec3_t lightGridOrigin; - vec3_t lightGridSize; - vec3_t lightGridInverseSize; - int lightGridBounds[3]; - byte *lightGridData; - - - int numClusters; - int clusterBytes; - const byte *vis; // may be passed in by CM_LoadMap to save space - - byte *novis; // clusterBytes of 0xff - - char *entityString; - char *entityParsePoint; -} world_t; - -//====================================================================== - -typedef enum { - MOD_BAD, - MOD_BRUSH, - MOD_MESH, - MOD_MDR, - MOD_IQM -} modtype_t; - -typedef struct model_s { - char name[MAX_QPATH]; - modtype_t type; - int index; // model = tr.models[model->index] - - int dataSize; // just for listing purposes - bmodel_t *bmodel; // only if type == MOD_BRUSH - md3Header_t *md3[MD3_MAX_LODS]; // only if type == MOD_MESH - void *modelData; // only if type == (MOD_MDR | MOD_IQM) - - int numLods; -} model_t; - - -#define MAX_MOD_KNOWN 1024 - -void R_ModelInit (void); -model_t *R_GetModelByHandle( qhandle_t hModel ); -int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, - float frac, const char *tagName ); -void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ); - -void R_Modellist_f (void); - -//==================================================== - -#define MAX_DRAWIMAGES 2048 -#define MAX_SKINS 1024 - - -#define MAX_DRAWSURFS 0x10000 -#define DRAWSURF_MASK (MAX_DRAWSURFS-1) - -/* - -the drawsurf sort data is packed into a single 32 bit value so it can be -compared quickly during the qsorting process - -the bits are allocated as follows: - -0 - 1 : dlightmap index -//2 : used to be clipped flag REMOVED - 03.21.00 rad -2 - 6 : fog index -11 - 20 : entity index -21 - 31 : sorted shader index - - TTimo - 1.32 -0-1 : dlightmap index -2-6 : fog index -7-16 : entity index -17-30 : sorted shader index -*/ -#define QSORT_FOGNUM_SHIFT 2 -#define QSORT_REFENTITYNUM_SHIFT 7 -#define QSORT_SHADERNUM_SHIFT (QSORT_REFENTITYNUM_SHIFT+REFENTITYNUM_BITS) -#if (QSORT_SHADERNUM_SHIFT+SHADERNUM_BITS) > 32 - #error "Need to update sorting, too many bits." -#endif - -extern int gl_filter_min, gl_filter_max; - -/* -** performanceCounters_t -*/ -typedef struct { - int c_sphere_cull_patch_in, c_sphere_cull_patch_clip, c_sphere_cull_patch_out; - int c_box_cull_patch_in, c_box_cull_patch_clip, c_box_cull_patch_out; - int c_sphere_cull_md3_in, c_sphere_cull_md3_clip, c_sphere_cull_md3_out; - int c_box_cull_md3_in, c_box_cull_md3_clip, c_box_cull_md3_out; - - int c_leafs; - int c_dlightSurfaces; - int c_dlightSurfacesCulled; -} frontEndCounters_t; - -#define FOG_TABLE_SIZE 256 -#define FUNCTABLE_SIZE 1024 -#define FUNCTABLE_SIZE2 10 -#define FUNCTABLE_MASK (FUNCTABLE_SIZE-1) - - -// the renderer front end should never modify glstate_t -typedef struct { - int currenttextures[2]; - int currenttmu; - qboolean finishCalled; - int texEnv[2]; - int faceCulling; - unsigned long glStateBits; -} glstate_t; - -typedef struct { - int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes; - float c_overDraw; - - int c_dlightVertexes; - int c_dlightIndexes; - - int c_flareAdds; - int c_flareTests; - int c_flareRenders; - - int msec; // total msec for backend run -} backEndCounters_t; - -// all state modified by the back end is seperated -// from the front end state -typedef struct { - trRefdef_t refdef; - viewParms_t viewParms; - orientationr_t or; - backEndCounters_t pc; - qboolean isHyperspace; - trRefEntity_t *currentEntity; - qboolean skyRenderedThisView; // flag for drawing sun - - qboolean projection2D; // if qtrue, drawstretchpic doesn't need to change modes - byte color2D[4]; - qboolean vertexes2D; // shader needs to be finished - trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering -} backEndState_t; - -/* -** trGlobals_t -** -** Most renderer globals are defined here. -** backend functions should never modify any of these fields, -** but may read fields that aren't dynamically modified -** by the frontend. -*/ -typedef struct { - qboolean registered; // cleared at shutdown, set at beginRegistration - - int visCount; // incremented every time a new vis cluster is entered - int frameCount; // incremented every frame - int sceneCount; // incremented every scene - int viewCount; // incremented every view (twice a scene if portaled) - // and every R_MarkFragments call - - int frameSceneNum; // zeroed at RE_BeginFrame - - qboolean worldMapLoaded; - world_t *world; - - const byte *externalVisData; // from RE_SetWorldVisData, shared with CM_Load - - image_t *defaultImage; - image_t *scratchImage[32]; - image_t *fogImage; - image_t *dlightImage; // inverse-quare highlight for projective adding - image_t *flareImage; - image_t *whiteImage; // full of 0xff - image_t *identityLightImage; // full of tr.identityLightByte - - shader_t *defaultShader; - shader_t *shadowShader; - shader_t *projectionShadowShader; - - shader_t *flareShader; - shader_t *sunShader; - - int numLightmaps; - image_t **lightmaps; - - trRefEntity_t *currentEntity; - trRefEntity_t worldEntity; // point currentEntity at this when rendering world - int currentEntityNum; - int shiftedEntityNum; // currentEntityNum << QSORT_REFENTITYNUM_SHIFT - model_t *currentModel; - - viewParms_t viewParms; - - float identityLight; // 1.0 / ( 1 << overbrightBits ) - int identityLightByte; // identityLight * 255 - int overbrightBits; // r_overbrightBits->integer, but set to 0 if no hw gamma - - orientationr_t or; // for current entity - - trRefdef_t refdef; - - int viewCluster; - - vec3_t sunLight; // from the sky shader for this level - vec3_t sunDirection; - - frontEndCounters_t pc; - int frontEndMsec; // not in pc due to clearing issue - - // - // put large tables at the end, so most elements will be - // within the +/32K indexed range on risc processors - // - model_t *models[MAX_MOD_KNOWN]; - int numModels; - - int numImages; - image_t *images[MAX_DRAWIMAGES]; - - // shader indexes from other modules will be looked up in tr.shaders[] - // shader indexes from drawsurfs will be looked up in sortedShaders[] - // lower indexed sortedShaders must be rendered first (opaque surfaces before translucent) - int numShaders; - shader_t *shaders[MAX_SHADERS]; - shader_t *sortedShaders[MAX_SHADERS]; - - int numSkins; - skin_t *skins[MAX_SKINS]; - - float sinTable[FUNCTABLE_SIZE]; - float squareTable[FUNCTABLE_SIZE]; - float triangleTable[FUNCTABLE_SIZE]; - float sawToothTable[FUNCTABLE_SIZE]; - float inverseSawToothTable[FUNCTABLE_SIZE]; - float fogTable[FOG_TABLE_SIZE]; -} trGlobals_t; - -extern backEndState_t backEnd; -extern trGlobals_t tr; -extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init - -// -// cvars -// -extern cvar_t *r_flareSize; -extern cvar_t *r_flareFade; -// coefficient for the flare intensity falloff function. -#define FLARE_STDCOEFF "150" -extern cvar_t *r_flareCoeff; - -extern cvar_t *r_railWidth; -extern cvar_t *r_railCoreWidth; -extern cvar_t *r_railSegmentLength; - -extern cvar_t *r_ignore; // used for debugging anything -extern cvar_t *r_verbose; // used for verbose debug spew -extern cvar_t *r_ignoreFastPath; // allows us to ignore our Tess fast paths - -extern cvar_t *r_znear; // near Z clip plane -extern cvar_t *r_zproj; // z distance of projection plane -extern cvar_t *r_stereoSeparation; // separation of cameras for stereo rendering - -extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement - -extern cvar_t *r_lodbias; // push/pull LOD transitions -extern cvar_t *r_lodscale; - -extern cvar_t *r_primitives; // "0" = based on compiled vertex array existance - // "1" = glDrawElemet tristrips - // "2" = glDrawElements triangles - // "-1" = no drawing - -extern cvar_t *r_inGameVideo; // controls whether in game video should be draw -extern cvar_t *r_fastsky; // controls whether sky should be cleared or drawn -extern cvar_t *r_drawSun; // controls drawing of sun quad -extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled -extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity - -extern cvar_t *r_norefresh; // bypasses the ref rendering -extern cvar_t *r_drawentities; // disable/enable entity rendering -extern cvar_t *r_drawworld; // disable/enable world rendering -extern cvar_t *r_speeds; // various levels of information display -extern cvar_t *r_detailTextures; // enables/disables detail texturing stages -extern cvar_t *r_novis; // disable/enable usage of PVS -extern cvar_t *r_nocull; -extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back side test -extern cvar_t *r_nocurves; -extern cvar_t *r_showcluster; - -extern cvar_t *r_gamma; - -extern cvar_t *r_nobind; // turns off binding to appropriate textures -extern cvar_t *r_singleShader; // make most world faces use default shader -extern cvar_t *r_roundImagesDown; -extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage -extern cvar_t *r_picmip; // controls picmip values -extern cvar_t *r_finish; -extern cvar_t *r_textureMode; -extern cvar_t *r_offsetFactor; -extern cvar_t *r_offsetUnits; - -extern cvar_t *r_fullbright; // avoid lightmap pass -extern cvar_t *r_lightmap; // render lightmaps only -extern cvar_t *r_vertexLight; // vertex lighting mode for better performance -extern cvar_t *r_uiFullScreen; // ui is running fullscreen - -extern cvar_t *r_logFile; // number of frames to emit GL logs -extern cvar_t *r_showtris; // enables wireframe rendering of the world -extern cvar_t *r_showsky; // forces sky in front of all surfaces -extern cvar_t *r_shownormals; // draws wireframe normals -extern cvar_t *r_clear; // force screen clear every frame - -extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection -extern cvar_t *r_flares; // light flares - -extern cvar_t *r_intensity; - -extern cvar_t *r_lockpvs; -extern cvar_t *r_noportals; -extern cvar_t *r_portalOnly; - -extern cvar_t *r_subdivisions; -extern cvar_t *r_lodCurveError; -extern cvar_t *r_skipBackEnd; - -extern cvar_t *r_anaglyphMode; - -extern cvar_t *r_greyscale; - -extern cvar_t *r_ignoreGLErrors; - -extern cvar_t *r_overBrightBits; -extern cvar_t *r_mapOverBrightBits; - -extern cvar_t *r_debugSurface; -extern cvar_t *r_simpleMipMaps; - -extern cvar_t *r_showImages; -extern cvar_t *r_debugSort; - -extern cvar_t *r_printShaders; - -extern cvar_t *r_marksOnTriangleMeshes; - -//==================================================================== - -void R_SwapBuffers( int ); - -void R_RenderView( viewParms_t *parms ); - -void R_AddMD3Surfaces( trRefEntity_t *e ); -void R_AddNullModelSurfaces( trRefEntity_t *e ); -void R_AddBeamSurfaces( trRefEntity_t *e ); -void R_AddRailSurfaces( trRefEntity_t *e, qboolean isUnderwater ); -void R_AddLightningBoltSurfaces( trRefEntity_t *e ); - -void R_AddPolygonSurfaces( void ); - -void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, - int *fogNum, int *dlightMap ); - -void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap ); - - -#define CULL_IN 0 // completely unclipped -#define CULL_CLIP 1 // clipped by one or more planes -#define CULL_OUT 2 // completely outside the clipping planes -void R_LocalNormalToWorld (vec3_t local, vec3_t world); -void R_LocalPointToWorld (vec3_t local, vec3_t world); -int R_CullLocalBox (vec3_t bounds[2]); -int R_CullPointAndRadius( vec3_t origin, float radius ); -int R_CullLocalPointAndRadius( vec3_t origin, float radius ); - -void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum); -void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *or ); - -/* -** GL wrapper/helper functions -*/ -void GL_Bind( image_t *image ); -void GL_SetDefaultState (void); -void GL_SelectTexture( int unit ); -void GL_TextureMode( const char *string ); -void GL_CheckErrors( void ); -void GL_State( unsigned long stateVector ); -void GL_TexEnv( int env ); -void GL_Cull( int cullType ); - -#define GLS_SRCBLEND_ZERO 0x00000001 -#define GLS_SRCBLEND_ONE 0x00000002 -#define GLS_SRCBLEND_DST_COLOR 0x00000003 -#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004 -#define GLS_SRCBLEND_SRC_ALPHA 0x00000005 -#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006 -#define GLS_SRCBLEND_DST_ALPHA 0x00000007 -#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008 -#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009 -#define GLS_SRCBLEND_BITS 0x0000000f - -#define GLS_DSTBLEND_ZERO 0x00000010 -#define GLS_DSTBLEND_ONE 0x00000020 -#define GLS_DSTBLEND_SRC_COLOR 0x00000030 -#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040 -#define GLS_DSTBLEND_SRC_ALPHA 0x00000050 -#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060 -#define GLS_DSTBLEND_DST_ALPHA 0x00000070 -#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080 -#define GLS_DSTBLEND_BITS 0x000000f0 - -#define GLS_DEPTHMASK_TRUE 0x00000100 - -#define GLS_POLYMODE_LINE 0x00001000 - -#define GLS_DEPTHTEST_DISABLE 0x00010000 -#define GLS_DEPTHFUNC_EQUAL 0x00020000 - -#define GLS_ATEST_GT_0 0x10000000 -#define GLS_ATEST_LT_80 0x20000000 -#define GLS_ATEST_GE_80 0x40000000 -#define GLS_ATEST_BITS 0x70000000 - -#define GLS_DEFAULT GLS_DEPTHMASK_TRUE - -void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); -void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); - -void RE_BeginFrame( stereoFrame_t stereoFrame ); -void RE_BeginRegistration( glconfig_t *glconfig ); -void RE_LoadWorldMap( const char *mapname ); -void RE_SetWorldVisData( const byte *vis ); -qhandle_t RE_RegisterModel( const char *name ); -qhandle_t RE_RegisterSkin( const char *name ); -void RE_Shutdown( qboolean destroyWindow ); - -qboolean R_GetEntityToken( char *buffer, int size ); - -model_t *R_AllocModel( void ); - -void R_Init( void ); - -void R_SetColorMappings( void ); -void R_GammaCorrect( byte *buffer, int bufSize ); - -void R_ImageList_f( void ); -void R_SkinList_f( void ); -// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516 -const void *RB_TakeScreenshotCmd( const void *data ); -void R_ScreenShot_f( void ); - -void R_InitFogTable( void ); -float R_FogFactor( float s, float t ); -void R_InitImages( void ); -void R_DeleteTextures( void ); -int R_SumOfUsedImages( void ); -void R_InitSkins( void ); -skin_t *R_GetSkinByHandle( qhandle_t hSkin ); - -int R_ComputeLOD( trRefEntity_t *ent ); - -const void *RB_TakeVideoFrameCmd( const void *data ); - -// -// tr_shader.c -// -shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ); -shader_t *R_GetShaderByHandle( qhandle_t hShader ); -shader_t *R_GetShaderByState( int index, long *cycleTime ); -shader_t *R_FindShaderByName( const char *name ); -void R_InitShaders( void ); -void R_ShaderList_f( void ); -void R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset); - -/* -==================================================================== - -TESSELATOR/SHADER DECLARATIONS - -==================================================================== -*/ -typedef byte color4ub_t[4]; - -typedef struct stageVars -{ - color4ub_t colors[SHADER_MAX_VERTEXES]; - vec2_t texcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES]; -} stageVars_t; - - -typedef struct shaderCommands_s -{ - glIndex_t indexes[SHADER_MAX_INDEXES] QALIGN(16); - vec4_t xyz[SHADER_MAX_VERTEXES] QALIGN(16); - vec4_t normal[SHADER_MAX_VERTEXES] QALIGN(16); - vec2_t texCoords[SHADER_MAX_VERTEXES][2] QALIGN(16); - color4ub_t vertexColors[SHADER_MAX_VERTEXES] QALIGN(16); - int vertexDlightBits[SHADER_MAX_VERTEXES] QALIGN(16); - - stageVars_t svars QALIGN(16); - - color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16); - - shader_t *shader; - float shaderTime; - int fogNum; - - int dlightBits; // or together of all vertexDlightBits - - int numIndexes; - int numVertexes; - - // info extracted from current shader - int numPasses; - void (*currentStageIteratorFunc)( void ); - shaderStage_t **xstages; -} shaderCommands_t; - -extern shaderCommands_t tess; - -void RB_BeginSurface(shader_t *shader, int fogNum ); -void RB_EndSurface(void); -void RB_CheckOverflow( int verts, int indexes ); -#define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);} - -void RB_StageIteratorGeneric( void ); -void RB_StageIteratorSky( void ); -void RB_StageIteratorVertexLitTexture( void ); -void RB_StageIteratorLightmappedMultitexture( void ); - -void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ); -void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ); - -void RB_ShowImages( void ); - - -/* -============================================================ - -WORLD MAP - -============================================================ -*/ - -void R_AddBrushModelSurfaces( trRefEntity_t *e ); -void R_AddWorldSurfaces( void ); -qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ); - - -/* -============================================================ - -FLARES - -============================================================ -*/ - -void R_ClearFlares( void ); - -void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ); -void RB_AddDlightFlares( void ); -void RB_RenderFlares (void); - -/* -============================================================ - -LIGHTS - -============================================================ -*/ - -void R_DlightBmodel( bmodel_t *bmodel ); -void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ); -void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or ); -int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); - - -/* -============================================================ - -SHADOWS - -============================================================ -*/ - -void RB_ShadowTessEnd( void ); -void RB_ShadowFinish( void ); -void RB_ProjectionShadowDeform( void ); - -/* -============================================================ - -SKIES - -============================================================ -*/ - -void R_BuildCloudData( shaderCommands_t *shader ); -void R_InitSkyTexCoords( float cloudLayerHeight ); -void R_DrawSkyBox( shaderCommands_t *shader ); -void RB_DrawSun( float scale, shader_t *shader ); -void RB_ClipSkyPolygons( shaderCommands_t *shader ); - -/* -============================================================ - -CURVE TESSELATION - -============================================================ -*/ - -#define PATCH_STITCHING - -srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, - drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ); -srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ); -srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ); -void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ); - -/* -============================================================ - -MARKERS, POLYGON PROJECTION ON WORLD POLYGONS - -============================================================ -*/ - -int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, - int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ); - - -/* -============================================================ - -SCENE GENERATION - -============================================================ -*/ - -void R_InitNextFrame( void ); - -void RE_ClearScene( void ); -void RE_AddRefEntityToScene( const refEntity_t *ent ); -void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ); -void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ); -void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ); -void RE_RenderScene( const refdef_t *fd ); - -/* -============================================================= - -UNCOMPRESSING BONES - -============================================================= -*/ - -#define MC_BITS_X (16) -#define MC_BITS_Y (16) -#define MC_BITS_Z (16) -#define MC_BITS_VECT (16) - -#define MC_SCALE_X (1.0f/64) -#define MC_SCALE_Y (1.0f/64) -#define MC_SCALE_Z (1.0f/64) - -void MC_UnCompress(float mat[3][4],const unsigned char * comp); - -/* -============================================================= - -ANIMATED MODELS - -============================================================= -*/ - -void R_MDRAddAnimSurfaces( trRefEntity_t *ent ); -void RB_MDRSurfaceAnim( mdrSurface_t *surface ); -qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name ); -void R_AddIQMSurfaces( trRefEntity_t *ent ); -void RB_IQMSurfaceAnim( surfaceType_t *surface ); -int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, - int startFrame, int endFrame, - float frac, const char *tagName ); - -/* -============================================================= - -IMAGE LOADERS - -============================================================= -*/ - -void R_LoadBMP( const char *name, byte **pic, int *width, int *height ); -void R_LoadJPG( const char *name, byte **pic, int *width, int *height ); -void R_LoadPCX( const char *name, byte **pic, int *width, int *height ); -void R_LoadPNG( const char *name, byte **pic, int *width, int *height ); -void R_LoadTGA( const char *name, byte **pic, int *width, int *height ); - -/* -============================================================= -============================================================= -*/ -void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix, - vec4_t eye, vec4_t dst ); -void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ); - -void RB_DeformTessGeometry( void ); - -void RB_CalcEnvironmentTexCoords( float *dstTexCoords ); -void RB_CalcFogTexCoords( float *dstTexCoords ); -void RB_CalcScrollTexCoords( const float scroll[2], float *dstTexCoords ); -void RB_CalcRotateTexCoords( float rotSpeed, float *dstTexCoords ); -void RB_CalcScaleTexCoords( const float scale[2], float *dstTexCoords ); -void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *dstTexCoords ); -void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *dstTexCoords ); -void RB_CalcModulateColorsByFog( unsigned char *dstColors ); -void RB_CalcModulateAlphasByFog( unsigned char *dstColors ); -void RB_CalcModulateRGBAsByFog( unsigned char *dstColors ); -void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors ); -void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors ); -void RB_CalcAlphaFromEntity( unsigned char *dstColors ); -void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors ); -void RB_CalcStretchTexCoords( const waveForm_t *wf, float *texCoords ); -void RB_CalcColorFromEntity( unsigned char *dstColors ); -void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors ); -void RB_CalcSpecularAlpha( unsigned char *alphas ); -void RB_CalcDiffuseColor( unsigned char *colors ); - -/* -============================================================= - -RENDERER BACK END FUNCTIONS - -============================================================= -*/ - -void RB_ExecuteRenderCommands( const void *data ); - -/* -============================================================= - -RENDERER BACK END COMMAND QUEUE - -============================================================= -*/ - -#define MAX_RENDER_COMMANDS 0x40000 - -typedef struct { - byte cmds[MAX_RENDER_COMMANDS]; - int used; -} renderCommandList_t; - -typedef struct { - int commandId; - float color[4]; -} setColorCommand_t; - -typedef struct { - int commandId; - int buffer; -} drawBufferCommand_t; - -typedef struct { - int commandId; - image_t *image; - int width; - int height; - void *data; -} subImageCommand_t; - -typedef struct { - int commandId; -} swapBuffersCommand_t; - -typedef struct { - int commandId; - int buffer; -} endFrameCommand_t; - -typedef struct { - int commandId; - shader_t *shader; - float x, y; - float w, h; - float s1, t1; - float s2, t2; -} stretchPicCommand_t; - -typedef struct { - int commandId; - trRefdef_t refdef; - viewParms_t viewParms; - drawSurf_t *drawSurfs; - int numDrawSurfs; -} drawSurfsCommand_t; - -typedef struct { - int commandId; - int x; - int y; - int width; - int height; - char *fileName; - qboolean jpeg; -} screenshotCommand_t; - -typedef struct { - int commandId; - int width; - int height; - byte *captureBuffer; - byte *encodeBuffer; - qboolean motionJpeg; -} videoFrameCommand_t; - -typedef struct -{ - int commandId; - - GLboolean rgba[4]; -} colorMaskCommand_t; - -typedef struct -{ - int commandId; -} clearDepthCommand_t; - -typedef enum { - RC_END_OF_LIST, - RC_SET_COLOR, - RC_STRETCH_PIC, - RC_DRAW_SURFS, - RC_DRAW_BUFFER, - RC_SWAP_BUFFERS, - RC_SCREENSHOT, - RC_VIDEOFRAME, - RC_COLORMASK, - RC_CLEARDEPTH -} renderCommand_t; - - -// these are sort of arbitrary limits. -// the limits apply to the sum of all scenes in a frame -- -// the main view, all the 3D icons, etc -#define MAX_POLYS 600 -#define MAX_POLYVERTS 3000 - -// all of the information needed by the back end must be -// contained in a backEndData_t -typedef struct { - drawSurf_t drawSurfs[MAX_DRAWSURFS]; - dlight_t dlights[MAX_DLIGHTS]; - trRefEntity_t entities[MAX_REFENTITIES]; - srfPoly_t *polys;//[MAX_POLYS]; - polyVert_t *polyVerts;//[MAX_POLYVERTS]; - renderCommandList_t commands; -} backEndData_t; - -extern int max_polys; -extern int max_polyverts; - -extern backEndData_t *backEndData; // the second one may not be allocated - - -void *R_GetCommandBuffer( int bytes ); -void RB_ExecuteRenderCommands( const void *data ); - -void R_IssuePendingRenderCommands( void ); - -void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ); - -void RE_SetColor( const float *rgba ); -void RE_StretchPic ( float x, float y, float w, float h, - float s1, float t1, float s2, float t2, qhandle_t hShader ); -void RE_BeginFrame( stereoFrame_t stereoFrame ); -void RE_EndFrame( int *frontEndMsec, int *backEndMsec ); -void RE_SaveJPG(char * filename, int quality, int image_width, int image_height, - unsigned char *image_buffer, int padding); -size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, - int image_width, int image_height, byte *image_buffer, int padding); -void RE_TakeVideoFrame( int width, int height, - byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ); - - -#endif //TR_LOCAL_H diff --git a/code/renderergl1/tr_main.c b/code/renderergl1/tr_main.c deleted file mode 100644 index 6a2118f169..0000000000 --- a/code/renderergl1/tr_main.c +++ /dev/null @@ -1,1389 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_main.c -- main control flow for each frame - -#include "tr_local.h" - -#include // memcpy - -trGlobals_t tr; - -static float s_flipMatrix[16] = { - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 -}; - - -refimport_t ri; - -// entities that will have procedurally generated surfaces will just -// point at this for their sorting surface -surfaceType_t entitySurface = SF_ENTITY; - -/* -================= -R_CullLocalBox - -Returns CULL_IN, CULL_CLIP, or CULL_OUT -================= -*/ -int R_CullLocalBox (vec3_t bounds[2]) { - int i, j; - vec3_t transformed[8]; - float dists[8]; - vec3_t v; - cplane_t *frust; - int anyBack; - int front, back; - - if ( r_nocull->integer ) { - return CULL_CLIP; - } - - // transform into world space - for (i = 0 ; i < 8 ; i++) { - v[0] = bounds[i&1][0]; - v[1] = bounds[(i>>1)&1][1]; - v[2] = bounds[(i>>2)&1][2]; - - VectorCopy( tr.or.origin, transformed[i] ); - VectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] ); - VectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] ); - VectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] ); - } - - // check against frustum planes - anyBack = 0; - for (i = 0 ; i < 4 ; i++) { - frust = &tr.viewParms.frustum[i]; - - front = back = 0; - for (j = 0 ; j < 8 ; j++) { - dists[j] = DotProduct(transformed[j], frust->normal); - if ( dists[j] > frust->dist ) { - front = 1; - if ( back ) { - break; // a point is in front - } - } else { - back = 1; - } - } - if ( !front ) { - // all points were behind one of the planes - return CULL_OUT; - } - anyBack |= back; - } - - if ( !anyBack ) { - return CULL_IN; // completely inside frustum - } - - return CULL_CLIP; // partially clipped -} - -/* -** R_CullLocalPointAndRadius -*/ -int R_CullLocalPointAndRadius( vec3_t pt, float radius ) -{ - vec3_t transformed; - - R_LocalPointToWorld( pt, transformed ); - - return R_CullPointAndRadius( transformed, radius ); -} - -/* -** R_CullPointAndRadius -*/ -int R_CullPointAndRadius( vec3_t pt, float radius ) -{ - int i; - float dist; - cplane_t *frust; - qboolean mightBeClipped = qfalse; - - if ( r_nocull->integer ) { - return CULL_CLIP; - } - - // check against frustum planes - for (i = 0 ; i < 4 ; i++) - { - frust = &tr.viewParms.frustum[i]; - - dist = DotProduct( pt, frust->normal) - frust->dist; - if ( dist < -radius ) - { - return CULL_OUT; - } - else if ( dist <= radius ) - { - mightBeClipped = qtrue; - } - } - - if ( mightBeClipped ) - { - return CULL_CLIP; - } - - return CULL_IN; // completely inside frustum -} - - -/* -================= -R_LocalNormalToWorld - -================= -*/ -void R_LocalNormalToWorld (vec3_t local, vec3_t world) { - world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0]; - world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1]; - world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2]; -} - -/* -================= -R_LocalPointToWorld - -================= -*/ -void R_LocalPointToWorld (vec3_t local, vec3_t world) { - world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0] + tr.or.origin[0]; - world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1] + tr.or.origin[1]; - world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2] + tr.or.origin[2]; -} - -/* -================= -R_WorldToLocal - -================= -*/ -void R_WorldToLocal (vec3_t world, vec3_t local) { - local[0] = DotProduct(world, tr.or.axis[0]); - local[1] = DotProduct(world, tr.or.axis[1]); - local[2] = DotProduct(world, tr.or.axis[2]); -} - -/* -========================== -R_TransformModelToClip - -========================== -*/ -void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix, - vec4_t eye, vec4_t dst ) { - int i; - - for ( i = 0 ; i < 4 ; i++ ) { - eye[i] = - src[0] * modelMatrix[ i + 0 * 4 ] + - src[1] * modelMatrix[ i + 1 * 4 ] + - src[2] * modelMatrix[ i + 2 * 4 ] + - 1 * modelMatrix[ i + 3 * 4 ]; - } - - for ( i = 0 ; i < 4 ; i++ ) { - dst[i] = - eye[0] * projectionMatrix[ i + 0 * 4 ] + - eye[1] * projectionMatrix[ i + 1 * 4 ] + - eye[2] * projectionMatrix[ i + 2 * 4 ] + - eye[3] * projectionMatrix[ i + 3 * 4 ]; - } -} - -/* -========================== -R_TransformClipToWindow - -========================== -*/ -void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) { - normalized[0] = clip[0] / clip[3]; - normalized[1] = clip[1] / clip[3]; - normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] ); - - window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth; - window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight; - window[2] = normalized[2]; - - window[0] = (int) ( window[0] + 0.5 ); - window[1] = (int) ( window[1] + 0.5 ); -} - - -/* -========================== -myGlMultMatrix - -========================== -*/ -void myGlMultMatrix( const float *a, const float *b, float *out ) { - int i, j; - - for ( i = 0 ; i < 4 ; i++ ) { - for ( j = 0 ; j < 4 ; j++ ) { - out[ i * 4 + j ] = - a [ i * 4 + 0 ] * b [ 0 * 4 + j ] - + a [ i * 4 + 1 ] * b [ 1 * 4 + j ] - + a [ i * 4 + 2 ] * b [ 2 * 4 + j ] - + a [ i * 4 + 3 ] * b [ 3 * 4 + j ]; - } - } -} - -/* -================= -R_RotateForEntity - -Generates an orientation for an entity and viewParms -Does NOT produce any GL calls -Called by both the front end and the back end -================= -*/ -void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, - orientationr_t *or ) { - float glMatrix[16]; - vec3_t delta; - float axisLength; - - if ( ent->e.reType != RT_MODEL ) { - *or = viewParms->world; - return; - } - - VectorCopy( ent->e.origin, or->origin ); - - VectorCopy( ent->e.axis[0], or->axis[0] ); - VectorCopy( ent->e.axis[1], or->axis[1] ); - VectorCopy( ent->e.axis[2], or->axis[2] ); - - glMatrix[0] = or->axis[0][0]; - glMatrix[4] = or->axis[1][0]; - glMatrix[8] = or->axis[2][0]; - glMatrix[12] = or->origin[0]; - - glMatrix[1] = or->axis[0][1]; - glMatrix[5] = or->axis[1][1]; - glMatrix[9] = or->axis[2][1]; - glMatrix[13] = or->origin[1]; - - glMatrix[2] = or->axis[0][2]; - glMatrix[6] = or->axis[1][2]; - glMatrix[10] = or->axis[2][2]; - glMatrix[14] = or->origin[2]; - - glMatrix[3] = 0; - glMatrix[7] = 0; - glMatrix[11] = 0; - glMatrix[15] = 1; - - myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix ); - - // calculate the viewer origin in the model's space - // needed for fog, specular, and environment mapping - VectorSubtract( viewParms->or.origin, or->origin, delta ); - - // compensate for scale in the axes if necessary - if ( ent->e.nonNormalizedAxes ) { - axisLength = VectorLength( ent->e.axis[0] ); - if ( !axisLength ) { - axisLength = 0; - } else { - axisLength = 1.0f / axisLength; - } - } else { - axisLength = 1.0f; - } - - or->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength; - or->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength; - or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength; -} - -/* -================= -R_RotateForViewer - -Sets up the modelview matrix for a given viewParm -================= -*/ -void R_RotateForViewer (void) -{ - float viewerMatrix[16]; - vec3_t origin; - - Com_Memset (&tr.or, 0, sizeof(tr.or)); - tr.or.axis[0][0] = 1; - tr.or.axis[1][1] = 1; - tr.or.axis[2][2] = 1; - VectorCopy (tr.viewParms.or.origin, tr.or.viewOrigin); - - // transform by the camera placement - VectorCopy( tr.viewParms.or.origin, origin ); - - viewerMatrix[0] = tr.viewParms.or.axis[0][0]; - viewerMatrix[4] = tr.viewParms.or.axis[0][1]; - viewerMatrix[8] = tr.viewParms.or.axis[0][2]; - viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8]; - - viewerMatrix[1] = tr.viewParms.or.axis[1][0]; - viewerMatrix[5] = tr.viewParms.or.axis[1][1]; - viewerMatrix[9] = tr.viewParms.or.axis[1][2]; - viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9]; - - viewerMatrix[2] = tr.viewParms.or.axis[2][0]; - viewerMatrix[6] = tr.viewParms.or.axis[2][1]; - viewerMatrix[10] = tr.viewParms.or.axis[2][2]; - viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10]; - - viewerMatrix[3] = 0; - viewerMatrix[7] = 0; - viewerMatrix[11] = 0; - viewerMatrix[15] = 1; - - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.or.modelMatrix ); - - tr.viewParms.world = tr.or; - -} - -/* -** SetFarClip -*/ -static void R_SetFarClip( void ) -{ - float farthestCornerDistance = 0; - int i; - - // if not rendering the world (icons, menus, etc) - // set a 2k far clip plane - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - tr.viewParms.zFar = 2048; - return; - } - - // - // set far clipping planes dynamically - // - farthestCornerDistance = 0; - for ( i = 0; i < 8; i++ ) - { - vec3_t v; - vec3_t vecTo; - float distance; - - if ( i & 1 ) - { - v[0] = tr.viewParms.visBounds[0][0]; - } - else - { - v[0] = tr.viewParms.visBounds[1][0]; - } - - if ( i & 2 ) - { - v[1] = tr.viewParms.visBounds[0][1]; - } - else - { - v[1] = tr.viewParms.visBounds[1][1]; - } - - if ( i & 4 ) - { - v[2] = tr.viewParms.visBounds[0][2]; - } - else - { - v[2] = tr.viewParms.visBounds[1][2]; - } - - VectorSubtract( v, tr.viewParms.or.origin, vecTo ); - - distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2]; - - if ( distance > farthestCornerDistance ) - { - farthestCornerDistance = distance; - } - } - tr.viewParms.zFar = sqrt( farthestCornerDistance ); -} - -/* -================= -R_SetupFrustum - -Set up the culling frustum planes for the current view using the results we got from computing the first two rows of -the projection matrix. -================= -*/ -void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float stereoSep) -{ - vec3_t ofsorigin; - float oppleg, adjleg, length; - int i; - - if(stereoSep == 0 && xmin == -xmax) - { - // symmetric case can be simplified - VectorCopy(dest->or.origin, ofsorigin); - - length = sqrt(xmax * xmax + zProj * zProj); - oppleg = xmax / length; - adjleg = zProj / length; - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[0].normal); - VectorMA(dest->frustum[0].normal, adjleg, dest->or.axis[1], dest->frustum[0].normal); - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[1].normal); - VectorMA(dest->frustum[1].normal, -adjleg, dest->or.axis[1], dest->frustum[1].normal); - } - else - { - // In stereo rendering, due to the modification of the projection matrix, dest->or.origin is not the - // actual origin that we're rendering so offset the tip of the view pyramid. - VectorMA(dest->or.origin, stereoSep, dest->or.axis[1], ofsorigin); - - oppleg = xmax + stereoSep; - length = sqrt(oppleg * oppleg + zProj * zProj); - VectorScale(dest->or.axis[0], oppleg / length, dest->frustum[0].normal); - VectorMA(dest->frustum[0].normal, zProj / length, dest->or.axis[1], dest->frustum[0].normal); - - oppleg = xmin + stereoSep; - length = sqrt(oppleg * oppleg + zProj * zProj); - VectorScale(dest->or.axis[0], -oppleg / length, dest->frustum[1].normal); - VectorMA(dest->frustum[1].normal, -zProj / length, dest->or.axis[1], dest->frustum[1].normal); - } - - length = sqrt(ymax * ymax + zProj * zProj); - oppleg = ymax / length; - adjleg = zProj / length; - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[2].normal); - VectorMA(dest->frustum[2].normal, adjleg, dest->or.axis[2], dest->frustum[2].normal); - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[3].normal); - VectorMA(dest->frustum[3].normal, -adjleg, dest->or.axis[2], dest->frustum[3].normal); - - for (i=0 ; i<4 ; i++) { - dest->frustum[i].type = PLANE_NON_AXIAL; - dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal); - SetPlaneSignbits( &dest->frustum[i] ); - } -} - -/* -=============== -R_SetupProjection -=============== -*/ -void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum) -{ - float xmin, xmax, ymin, ymax; - float width, height, stereoSep = r_stereoSeparation->value; - - /* - * offset the view origin of the viewer for stereo rendering - * by setting the projection matrix appropriately. - */ - - if(stereoSep != 0) - { - if(dest->stereoFrame == STEREO_LEFT) - stereoSep = zProj / stereoSep; - else if(dest->stereoFrame == STEREO_RIGHT) - stereoSep = zProj / -stereoSep; - else - stereoSep = 0; - } - - ymax = zProj * tan(dest->fovY * M_PI / 360.0f); - ymin = -ymax; - - xmax = zProj * tan(dest->fovX * M_PI / 360.0f); - xmin = -xmax; - - width = xmax - xmin; - height = ymax - ymin; - - dest->projectionMatrix[0] = 2 * zProj / width; - dest->projectionMatrix[4] = 0; - dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width; - dest->projectionMatrix[12] = 2 * zProj * stereoSep / width; - - dest->projectionMatrix[1] = 0; - dest->projectionMatrix[5] = 2 * zProj / height; - dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0 - dest->projectionMatrix[13] = 0; - - dest->projectionMatrix[3] = 0; - dest->projectionMatrix[7] = 0; - dest->projectionMatrix[11] = -1; - dest->projectionMatrix[15] = 0; - - // Now that we have all the data for the projection matrix we can also setup the view frustum. - if(computeFrustum) - R_SetupFrustum(dest, xmin, xmax, ymax, zProj, stereoSep); -} - -/* -=============== -R_SetupProjectionZ - -Sets the z-component transformation part in the projection matrix -=============== -*/ -void R_SetupProjectionZ(viewParms_t *dest) -{ - float zNear, zFar, depth; - - zNear = r_znear->value; - zFar = dest->zFar; - depth = zFar - zNear; - - dest->projectionMatrix[2] = 0; - dest->projectionMatrix[6] = 0; - dest->projectionMatrix[10] = -( zFar + zNear ) / depth; - dest->projectionMatrix[14] = -2 * zFar * zNear / depth; -} - -/* -================= -R_MirrorPoint -================= -*/ -void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { - int i; - vec3_t local; - vec3_t transformed; - float d; - - VectorSubtract( in, surface->origin, local ); - - VectorClear( transformed ); - for ( i = 0 ; i < 3 ; i++ ) { - d = DotProduct(local, surface->axis[i]); - VectorMA( transformed, d, camera->axis[i], transformed ); - } - - VectorAdd( transformed, camera->origin, out ); -} - -void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { - int i; - float d; - - VectorClear( out ); - for ( i = 0 ; i < 3 ; i++ ) { - d = DotProduct(in, surface->axis[i]); - VectorMA( out, d, camera->axis[i], out ); - } -} - - -/* -============= -R_PlaneForSurface -============= -*/ -void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) { - srfTriangles_t *tri; - srfPoly_t *poly; - drawVert_t *v1, *v2, *v3; - vec4_t plane4; - - if (!surfType) { - Com_Memset (plane, 0, sizeof(*plane)); - plane->normal[0] = 1; - return; - } - switch (*surfType) { - case SF_FACE: - *plane = ((srfSurfaceFace_t *)surfType)->plane; - return; - case SF_TRIANGLES: - tri = (srfTriangles_t *)surfType; - v1 = tri->verts + tri->indexes[0]; - v2 = tri->verts + tri->indexes[1]; - v3 = tri->verts + tri->indexes[2]; - PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz ); - VectorCopy( plane4, plane->normal ); - plane->dist = plane4[3]; - return; - case SF_POLY: - poly = (srfPoly_t *)surfType; - PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz ); - VectorCopy( plane4, plane->normal ); - plane->dist = plane4[3]; - return; - default: - Com_Memset (plane, 0, sizeof(*plane)); - plane->normal[0] = 1; - return; - } -} - -/* -================= -R_GetPortalOrientation - -entityNum is the entity that the portal surface is a part of, which may -be moving and rotating. - -Returns qtrue if it should be mirrored -================= -*/ -qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum, - orientation_t *surface, orientation_t *camera, - vec3_t pvsOrigin, qboolean *mirror ) { - int i; - cplane_t originalPlane, plane; - trRefEntity_t *e; - float d; - vec3_t transformed; - - // create plane axis for the portal we are seeing - R_PlaneForSurface( drawSurf->surface, &originalPlane ); - - // rotate the plane if necessary - if ( entityNum != REFENTITYNUM_WORLD ) { - tr.currentEntityNum = entityNum; - tr.currentEntity = &tr.refdef.entities[entityNum]; - - // get the orientation of the entity - R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); - - // rotate the plane, but keep the non-rotated version for matching - // against the portalSurface entities - R_LocalNormalToWorld( originalPlane.normal, plane.normal ); - plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); - - // translate the original plane - originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); - } else { - plane = originalPlane; - } - - VectorCopy( plane.normal, surface->axis[0] ); - PerpendicularVector( surface->axis[1], surface->axis[0] ); - CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] ); - - // locate the portal entity closest to this plane. - // origin will be the origin of the portal, origin2 will be - // the origin of the camera - for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) { - e = &tr.refdef.entities[i]; - if ( e->e.reType != RT_PORTALSURFACE ) { - continue; - } - - d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; - if ( d > 64 || d < -64) { - continue; - } - - // get the pvsOrigin from the entity - VectorCopy( e->e.oldorigin, pvsOrigin ); - - // if the entity is just a mirror, don't use as a camera point - if ( e->e.oldorigin[0] == e->e.origin[0] && - e->e.oldorigin[1] == e->e.origin[1] && - e->e.oldorigin[2] == e->e.origin[2] ) { - VectorScale( plane.normal, plane.dist, surface->origin ); - VectorCopy( surface->origin, camera->origin ); - VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] ); - VectorCopy( surface->axis[1], camera->axis[1] ); - VectorCopy( surface->axis[2], camera->axis[2] ); - - *mirror = qtrue; - return qtrue; - } - - // project the origin onto the surface plane to get - // an origin point we can rotate around - d = DotProduct( e->e.origin, plane.normal ) - plane.dist; - VectorMA( e->e.origin, -d, surface->axis[0], surface->origin ); - - // now get the camera origin and orientation - VectorCopy( e->e.oldorigin, camera->origin ); - AxisCopy( e->e.axis, camera->axis ); - VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] ); - VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] ); - - // optionally rotate - if ( e->e.oldframe ) { - // if a speed is specified - if ( e->e.frame ) { - // continuous rotate - d = (tr.refdef.time/1000.0f) * e->e.frame; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } else { - // bobbing rotate, with skinNum being the rotation offset - d = sin( tr.refdef.time * 0.003f ); - d = e->e.skinNum + d * 4; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } - } - else if ( e->e.skinNum ) { - d = e->e.skinNum; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } - *mirror = qfalse; - return qtrue; - } - - // if we didn't locate a portal entity, don't render anything. - // We don't want to just treat it as a mirror, because without a - // portal entity the server won't have communicated a proper entity set - // in the snapshot - - // unfortunately, with local movement prediction it is easily possible - // to see a surface before the server has communicated the matching - // portal surface entity, so we don't want to print anything here... - - //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" ); - - return qfalse; -} - -static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum ) -{ - int i; - cplane_t originalPlane, plane; - trRefEntity_t *e; - float d; - - // create plane axis for the portal we are seeing - R_PlaneForSurface( drawSurf->surface, &originalPlane ); - - // rotate the plane if necessary - if ( entityNum != REFENTITYNUM_WORLD ) - { - tr.currentEntityNum = entityNum; - tr.currentEntity = &tr.refdef.entities[entityNum]; - - // get the orientation of the entity - R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); - - // rotate the plane, but keep the non-rotated version for matching - // against the portalSurface entities - R_LocalNormalToWorld( originalPlane.normal, plane.normal ); - plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); - - // translate the original plane - originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); - } - - // locate the portal entity closest to this plane. - // origin will be the origin of the portal, origin2 will be - // the origin of the camera - for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) - { - e = &tr.refdef.entities[i]; - if ( e->e.reType != RT_PORTALSURFACE ) { - continue; - } - - d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; - if ( d > 64 || d < -64) { - continue; - } - - // if the entity is just a mirror, don't use as a camera point - if ( e->e.oldorigin[0] == e->e.origin[0] && - e->e.oldorigin[1] == e->e.origin[1] && - e->e.oldorigin[2] == e->e.origin[2] ) - { - return qtrue; - } - - return qfalse; - } - return qfalse; -} - -/* -** SurfIsOffscreen -** -** Determines if a surface is completely offscreen. -*/ -static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) { - float shortest = 100000000; - int entityNum; - int numTriangles; - shader_t *shader; - int fogNum; - int dlighted; - vec4_t clip, eye; - int i; - unsigned int pointOr = 0; - unsigned int pointAnd = (unsigned int)~0; - - R_RotateForViewer(); - - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); - RB_BeginSurface( shader, fogNum ); - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - - assert( tess.numVertexes < 128 ); - - for ( i = 0; i < tess.numVertexes; i++ ) - { - int j; - unsigned int pointFlags = 0; - - R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip ); - - for ( j = 0; j < 3; j++ ) - { - if ( clip[j] >= clip[3] ) - { - pointFlags |= (1 << (j*2)); - } - else if ( clip[j] <= -clip[3] ) - { - pointFlags |= ( 1 << (j*2+1)); - } - } - pointAnd &= pointFlags; - pointOr |= pointFlags; - } - - // trivially reject - if ( pointAnd ) - { - return qtrue; - } - - // determine if this surface is backfaced and also determine the distance - // to the nearest vertex so we can cull based on portal range. Culling - // based on vertex distance isn't 100% correct (we should be checking for - // range to the surface), but it's good enough for the types of portals - // we have in the game right now. - numTriangles = tess.numIndexes / 3; - - for ( i = 0; i < tess.numIndexes; i += 3 ) - { - vec3_t normal; - float len; - - VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal ); - - len = VectorLengthSquared( normal ); // lose the sqrt - if ( len < shortest ) - { - shortest = len; - } - - if ( DotProduct( normal, tess.normal[tess.indexes[i]] ) >= 0 ) - { - numTriangles--; - } - } - if ( !numTriangles ) - { - return qtrue; - } - - // mirrors can early out at this point, since we don't do a fade over distance - // with them (although we could) - if ( IsMirror( drawSurf, entityNum ) ) - { - return qfalse; - } - - if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) ) - { - return qtrue; - } - - return qfalse; -} - -/* -======================== -R_MirrorViewBySurface - -Returns qtrue if another view has been rendered -======================== -*/ -qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) { - vec4_t clipDest[128]; - viewParms_t newParms; - viewParms_t oldParms; - orientation_t surface, camera; - - // don't recursively mirror - if (tr.viewParms.isPortal) { - ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" ); - return qfalse; - } - - if ( r_noportals->integer || (r_fastsky->integer == 1) ) { - return qfalse; - } - - // trivially reject portal/mirror - if ( SurfIsOffscreen( drawSurf, clipDest ) ) { - return qfalse; - } - - // save old viewParms so we can return to it after the mirror view - oldParms = tr.viewParms; - - newParms = tr.viewParms; - newParms.isPortal = qtrue; - if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera, - newParms.pvsOrigin, &newParms.isMirror ) ) { - return qfalse; // bad portal, no portalentity - } - - R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); - - VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal ); - newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal ); - - R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]); - R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]); - R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]); - - // OPTIMIZE: restrict the viewport on the mirrored view - - // render the mirror view - R_RenderView (&newParms); - - tr.viewParms = oldParms; - - return qtrue; -} - -/* -================= -R_SpriteFogNum - -See if a sprite is inside a fog volume -================= -*/ -int R_SpriteFogNum( trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) { - break; - } - if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -========================================================================================== - -DRAWSURF SORTING - -========================================================================================== -*/ - -/* -=============== -R_Radix -=============== -*/ -static ID_INLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest ) -{ - int count[ 256 ] = { 0 }; - int index[ 256 ]; - int i; - unsigned char *sortKey = NULL; - unsigned char *end = NULL; - - sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte; - end = sortKey + ( size * sizeof( drawSurf_t ) ); - for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) ) - ++count[ *sortKey ]; - - index[ 0 ] = 0; - - for( i = 1; i < 256; ++i ) - index[ i ] = index[ i - 1 ] + count[ i - 1 ]; - - sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte; - for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) ) - dest[ index[ *sortKey ]++ ] = source[ i ]; -} - -/* -=============== -R_RadixSort - -Radix sort with 4 byte size buckets -=============== -*/ -static void R_RadixSort( drawSurf_t *source, int size ) -{ - static drawSurf_t scratch[ MAX_DRAWSURFS ]; -#ifdef Q3_LITTLE_ENDIAN - R_Radix( 0, size, source, scratch ); - R_Radix( 1, size, scratch, source ); - R_Radix( 2, size, source, scratch ); - R_Radix( 3, size, scratch, source ); -#else - R_Radix( 3, size, source, scratch ); - R_Radix( 2, size, scratch, source ); - R_Radix( 1, size, source, scratch ); - R_Radix( 0, size, scratch, source ); -#endif //Q3_LITTLE_ENDIAN -} - -//========================================================================================== - -/* -================= -R_AddDrawSurf -================= -*/ -void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, - int fogIndex, int dlightMap ) { - int index; - - // instead of checking for overflow, we just mask the index - // so it wraps around - index = tr.refdef.numDrawSurfs & DRAWSURF_MASK; - // the sort data is packed into a single 32 bit value so it can be - // compared quickly during the qsorting process - tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT) - | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | (int)dlightMap; - tr.refdef.drawSurfs[index].surface = surface; - tr.refdef.numDrawSurfs++; -} - -/* -================= -R_DecomposeSort -================= -*/ -void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, - int *fogNum, int *dlightMap ) { - *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31; - *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ]; - *entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK; - *dlightMap = sort & 3; -} - -/* -================= -R_SortDrawSurfs -================= -*/ -void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { - shader_t *shader; - int fogNum; - int entityNum; - int dlighted; - int i; - - // it is possible for some views to not have any surfaces - if ( numDrawSurfs < 1 ) { - // we still need to add it for hyperspace cases - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); - return; - } - - // if we overflowed MAX_DRAWSURFS, the drawsurfs - // wrapped around in the buffer and we will be missing - // the first surfaces, not the last ones - if ( numDrawSurfs > MAX_DRAWSURFS ) { - numDrawSurfs = MAX_DRAWSURFS; - } - - // sort the drawsurfs by sort type, then orientation, then shader - R_RadixSort( drawSurfs, numDrawSurfs ); - - // check for any pass through drawing, which - // may cause another view to be rendered first - for ( i = 0 ; i < numDrawSurfs ; i++ ) { - R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted ); - - if ( shader->sort > SS_PORTAL ) { - break; - } - - // no shader should ever have this sort type - if ( shader->sort == SS_BAD ) { - ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name ); - } - - // if the mirror was completely clipped away, we may need to check another surface - if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) { - // this is a debug option to see exactly what is being mirrored - if ( r_portalOnly->integer ) { - return; - } - break; // only one mirror view at a time - } - } - - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); -} - -/* -============= -R_AddEntitySurfaces -============= -*/ -void R_AddEntitySurfaces (void) { - trRefEntity_t *ent; - shader_t *shader; - - if ( !r_drawentities->integer ) { - return; - } - - for ( tr.currentEntityNum = 0; - tr.currentEntityNum < tr.refdef.num_entities; - tr.currentEntityNum++ ) { - ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum]; - - ent->needDlights = qfalse; - - // preshift the value we are going to OR into the drawsurf sort - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - - // - // the weapon model must be handled special -- - // we don't want the hacked weapon position showing in - // mirrors, because the true body position will already be drawn - // - if ( (ent->e.renderfx & RF_FIRST_PERSON) && tr.viewParms.isPortal) { - continue; - } - - // simple generated models, like sprites and beams, are not culled - switch ( ent->e.reType ) { - case RT_PORTALSURFACE: - break; // don't draw anything - case RT_SPRITE: - case RT_BEAM: - case RT_LIGHTNING: - case RT_RAIL_CORE: - case RT_RAIL_RINGS: - // self blood sprites, talk balloons, etc should not be drawn in the primary - // view. We can't just do this check for all entities, because md3 - // entities may still want to cast shadows from them - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - continue; - } - shader = R_GetShaderByHandle( ent->e.customShader ); - R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0 ); - break; - - case RT_MODEL: - // we must set up parts of tr.or for model culling - R_RotateForEntity( ent, &tr.viewParms, &tr.or ); - - tr.currentModel = R_GetModelByHandle( ent->e.hModel ); - if (!tr.currentModel) { - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 ); - } else { - switch ( tr.currentModel->type ) { - case MOD_MESH: - R_AddMD3Surfaces( ent ); - break; - case MOD_MDR: - R_MDRAddAnimSurfaces( ent ); - break; - case MOD_IQM: - R_AddIQMSurfaces( ent ); - break; - case MOD_BRUSH: - R_AddBrushModelSurfaces( ent ); - break; - case MOD_BAD: // null model axis - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - break; - } - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 ); - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" ); - break; - } - } - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" ); - } - } - -} - - -/* -==================== -R_GenerateDrawSurfs -==================== -*/ -void R_GenerateDrawSurfs( void ) { - R_AddWorldSurfaces (); - - R_AddPolygonSurfaces(); - - // set the projection matrix with the minimum zfar - // now that we have the world bounded - // this needs to be done before entities are - // added, because they use the projection - // matrix for lod calculation - - // dynamically compute far clip plane distance - R_SetFarClip(); - - // we know the size of the clipping volume. Now set the rest of the projection matrix. - R_SetupProjectionZ (&tr.viewParms); - - R_AddEntitySurfaces (); -} - -/* -================ -R_DebugPolygon -================ -*/ -void R_DebugPolygon( int color, int numPoints, float *points ) { - int i; - - GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - // draw solid shade - - qglColor3f( color&1, (color>>1)&1, (color>>2)&1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); - - // draw wireframe outline - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - qglDepthRange( 0, 0 ); - qglColor3f( 1, 1, 1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); - qglDepthRange( 0, 1 ); -} - -/* -==================== -R_DebugGraphics - -Visualization aid for movement clipping debugging -==================== -*/ -void R_DebugGraphics( void ) { - if ( !r_debugSurface->integer ) { - return; - } - - R_IssuePendingRenderCommands(); - - GL_Bind( tr.whiteImage); - GL_Cull( CT_FRONT_SIDED ); - ri.CM_DrawDebugSurface( R_DebugPolygon ); -} - - -/* -================ -R_RenderView - -A view may be either the actual camera view, -or a mirror / remote location -================ -*/ -void R_RenderView (viewParms_t *parms) { - int firstDrawSurf; - - if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) { - return; - } - - tr.viewCount++; - - tr.viewParms = *parms; - tr.viewParms.frameSceneNum = tr.frameSceneNum; - tr.viewParms.frameCount = tr.frameCount; - - firstDrawSurf = tr.refdef.numDrawSurfs; - - tr.viewCount++; - - // set viewParms.world - R_RotateForViewer (); - - R_SetupProjection(&tr.viewParms, r_zproj->value, qtrue); - - R_GenerateDrawSurfs(); - - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); - - // draw main system development information (surface outlines, etc) - R_DebugGraphics(); -} - - - diff --git a/code/renderergl1/tr_marks.c b/code/renderergl1/tr_marks.c deleted file mode 100644 index e2c92b6c72..0000000000 --- a/code/renderergl1/tr_marks.c +++ /dev/null @@ -1,458 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_marks.c -- polygon projection on the world polygons - -#include "tr_local.h" -//#include "assert.h" - -#define MAX_VERTS_ON_POLY 64 - -#define MARKER_OFFSET 0 // 1 - -/* -============= -R_ChopPolyBehindPlane - -Out must have space for two more vertexes than in -============= -*/ -#define SIDE_FRONT 0 -#define SIDE_BACK 1 -#define SIDE_ON 2 -static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY], - int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY], - vec3_t normal, vec_t dist, vec_t epsilon) { - float dists[MAX_VERTS_ON_POLY+4] = { 0 }; - int sides[MAX_VERTS_ON_POLY+4] = { 0 }; - int counts[3]; - float dot; - int i, j; - float *p1, *p2, *clip; - float d; - - // don't clip if it might overflow - if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) { - *numOutPoints = 0; - return; - } - - counts[0] = counts[1] = counts[2] = 0; - - // determine sides for each point - for ( i = 0 ; i < numInPoints ; i++ ) { - dot = DotProduct( inPoints[i], normal ); - dot -= dist; - dists[i] = dot; - if ( dot > epsilon ) { - sides[i] = SIDE_FRONT; - } else if ( dot < -epsilon ) { - sides[i] = SIDE_BACK; - } else { - sides[i] = SIDE_ON; - } - counts[sides[i]]++; - } - sides[i] = sides[0]; - dists[i] = dists[0]; - - *numOutPoints = 0; - - if ( !counts[0] ) { - return; - } - if ( !counts[1] ) { - *numOutPoints = numInPoints; - Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) ); - return; - } - - for ( i = 0 ; i < numInPoints ; i++ ) { - p1 = inPoints[i]; - clip = outPoints[ *numOutPoints ]; - - if ( sides[i] == SIDE_ON ) { - VectorCopy( p1, clip ); - (*numOutPoints)++; - continue; - } - - if ( sides[i] == SIDE_FRONT ) { - VectorCopy( p1, clip ); - (*numOutPoints)++; - clip = outPoints[ *numOutPoints ]; - } - - if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) { - continue; - } - - // generate a split point - p2 = inPoints[ (i+1) % numInPoints ]; - - d = dists[i] - dists[i+1]; - if ( d == 0 ) { - dot = 0; - } else { - dot = dists[i] / d; - } - - // clip xyz - - for (j=0 ; j<3 ; j++) { - clip[j] = p1[j] + dot * ( p2[j] - p1[j] ); - } - - (*numOutPoints)++; - } -} - -/* -================= -R_BoxSurfaces_r - -================= -*/ -void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) { - - int s, c; - msurface_t *surf, **mark; - - // do the tail recursion in a loop - while ( node->contents == -1 ) { - s = BoxOnPlaneSide( mins, maxs, node->plane ); - if (s == 1) { - node = node->children[0]; - } else if (s == 2) { - node = node->children[1]; - } else { - R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir); - node = node->children[1]; - } - } - - // add the individual surfaces - mark = node->firstmarksurface; - c = node->nummarksurfaces; - while (c--) { - // - if (*listlength >= listsize) break; - // - surf = *mark; - // check if the surface has NOIMPACT or NOMARKS set - if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) ) - || ( surf->shader->contentFlags & CONTENTS_FOG ) ) { - surf->viewCount = tr.viewCount; - } - // extra check for surfaces to avoid list overflows - else if (*(surf->data) == SF_FACE) { - // the face plane should go through the box - s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane ); - if (s == 1 || s == 2) { - surf->viewCount = tr.viewCount; - } else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) { - // don't add faces that make sharp angles with the projection direction - surf->viewCount = tr.viewCount; - } - } - else if (*(surfaceType_t *) (surf->data) != SF_GRID && - *(surfaceType_t *) (surf->data) != SF_TRIANGLES) - surf->viewCount = tr.viewCount; - // check the viewCount because the surface may have - // already been added if it spans multiple leafs - if (surf->viewCount != tr.viewCount) { - surf->viewCount = tr.viewCount; - list[*listlength] = (surfaceType_t *) surf->data; - (*listlength)++; - } - mark++; - } -} - -/* -================= -R_AddMarkFragments - -================= -*/ -void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY], - int numPlanes, vec3_t *normals, float *dists, - int maxPoints, vec3_t pointBuffer, - int maxFragments, markFragment_t *fragmentBuffer, - int *returnedPoints, int *returnedFragments, - vec3_t mins, vec3_t maxs) { - int pingPong, i; - markFragment_t *mf; - - // chop the surface by all the bounding planes of the to be projected polygon - pingPong = 0; - - for ( i = 0 ; i < numPlanes ; i++ ) { - - R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong], - &numClipPoints, clipPoints[!pingPong], - normals[i], dists[i], 0.5 ); - pingPong ^= 1; - if ( numClipPoints == 0 ) { - break; - } - } - // completely clipped away? - if ( numClipPoints == 0 ) { - return; - } - - // add this fragment to the returned list - if ( numClipPoints + (*returnedPoints) > maxPoints ) { - return; // not enough space for this polygon - } - /* - // all the clip points should be within the bounding box - for ( i = 0 ; i < numClipPoints ; i++ ) { - int j; - for ( j = 0 ; j < 3 ; j++ ) { - if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break; - if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break; - } - if (j < 3) break; - } - if (i < numClipPoints) return; - */ - - mf = fragmentBuffer + (*returnedFragments); - mf->firstPoint = (*returnedPoints); - mf->numPoints = numClipPoints; - Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) ); - - (*returnedPoints) += numClipPoints; - (*returnedFragments)++; -} - -/* -================= -R_MarkFragments - -================= -*/ -int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, - int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) { - int numsurfaces, numPlanes; - int i, j, k, m, n; - surfaceType_t *surfaces[64]; - vec3_t mins, maxs; - int returnedFragments; - int returnedPoints; - vec3_t normals[MAX_VERTS_ON_POLY+2]; - float dists[MAX_VERTS_ON_POLY+2]; - vec3_t clipPoints[2][MAX_VERTS_ON_POLY]; - int numClipPoints; - float *v; - srfGridMesh_t *cv; - drawVert_t *dv; - vec3_t normal; - vec3_t projectionDir; - vec3_t v1, v2; - int *indexes; - - if (numPoints <= 0) { - return 0; - } - - //increment view count for double check prevention - tr.viewCount++; - - // - VectorNormalize2( projection, projectionDir ); - // find all the brushes that are to be considered - ClearBounds( mins, maxs ); - for ( i = 0 ; i < numPoints ; i++ ) { - vec3_t temp; - - AddPointToBounds( points[i], mins, maxs ); - VectorAdd( points[i], projection, temp ); - AddPointToBounds( temp, mins, maxs ); - // make sure we get all the leafs (also the one(s) in front of the hit surface) - VectorMA( points[i], -20, projectionDir, temp ); - AddPointToBounds( temp, mins, maxs ); - } - - if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY; - // create the bounding planes for the to be projected polygon - for ( i = 0 ; i < numPoints ; i++ ) { - VectorSubtract(points[(i+1)%numPoints], points[i], v1); - VectorAdd(points[i], projection, v2); - VectorSubtract(points[i], v2, v2); - CrossProduct(v1, v2, normals[i]); - VectorNormalizeFast(normals[i]); - dists[i] = DotProduct(normals[i], points[i]); - } - // add near and far clipping planes for projection - VectorCopy(projectionDir, normals[numPoints]); - dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32; - VectorCopy(projectionDir, normals[numPoints+1]); - VectorInverse(normals[numPoints+1]); - dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20; - numPlanes = numPoints + 2; - - numsurfaces = 0; - R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir); - //assert(numsurfaces <= 64); - //assert(numsurfaces != 64); - - returnedPoints = 0; - returnedFragments = 0; - - for ( i = 0 ; i < numsurfaces ; i++ ) { - - if (*surfaces[i] == SF_GRID) { - - cv = (srfGridMesh_t *) surfaces[i]; - for ( m = 0 ; m < cv->height - 1 ; m++ ) { - for ( n = 0 ; n < cv->width - 1 ; n++ ) { - // We triangulate the grid and chop all triangles within - // the bounding planes of the to be projected polygon. - // LOD is not taken into account, not such a big deal though. - // - // It's probably much nicer to chop the grid itself and deal - // with this grid as a normal SF_GRID surface so LOD will - // be applied. However the LOD of that chopped grid must - // be synced with the LOD of the original curve. - // One way to do this; the chopped grid shares vertices with - // the original curve. When LOD is applied to the original - // curve the unused vertices are flagged. Now the chopped curve - // should skip the flagged vertices. This still leaves the - // problems with the vertices at the chopped grid edges. - // - // To avoid issues when LOD applied to "hollow curves" (like - // the ones around many jump pads) we now just add a 2 unit - // offset to the triangle vertices. - // The offset is added in the vertex normal vector direction - // so all triangles will still fit together. - // The 2 unit offset should avoid pretty much all LOD problems. - - numClipPoints = 3; - - dv = cv->verts + m * cv->width + n; - - VectorCopy(dv[0].xyz, clipPoints[0][0]); - VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]); - VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); - VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); - VectorCopy(dv[1].xyz, clipPoints[0][2]); - VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]); - // check the normal of this triangle - VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); - VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); - CrossProduct(v1, v2, normal); - VectorNormalizeFast(normal); - if (DotProduct(normal, projectionDir) < -0.1) { - // add the fragments of this triangle - R_AddMarkFragments(numClipPoints, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - - VectorCopy(dv[1].xyz, clipPoints[0][0]); - VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]); - VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); - VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); - VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]); - VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]); - // check the normal of this triangle - VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); - VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); - CrossProduct(v1, v2, normal); - VectorNormalizeFast(normal); - if (DotProduct(normal, projectionDir) < -0.05) { - // add the fragments of this triangle - R_AddMarkFragments(numClipPoints, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - } - } - } - else if (*surfaces[i] == SF_FACE) { - - srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i]; - - // check the normal of this face - if (DotProduct(surf->plane.normal, projectionDir) > -0.5) { - continue; - } - - indexes = (int *)( (byte *)surf + surf->ofsIndices ); - for ( k = 0 ; k < surf->numIndices ; k += 3 ) { - for ( j = 0 ; j < 3 ; j++ ) { - v = surf->points[0] + VERTEXSIZE * indexes[k+j];; - VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] ); - } - - // add the fragments of this face - R_AddMarkFragments( 3 , clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - } - else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) { - - srfTriangles_t *surf = (srfTriangles_t *) surfaces[i]; - - for (k = 0; k < surf->numIndexes; k += 3) - { - for(j = 0; j < 3; j++) - { - v = surf->verts[surf->indexes[k + j]].xyz; - VectorMA(v, MARKER_OFFSET, surf->verts[surf->indexes[k + j]].normal, clipPoints[0][j]); - } - - // add the fragments of this face - R_AddMarkFragments(3, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); - if(returnedFragments == maxFragments) - { - return returnedFragments; // not enough space for more fragments - } - } - } - } - return returnedFragments; -} - diff --git a/code/renderergl1/tr_mesh.c b/code/renderergl1/tr_mesh.c deleted file mode 100644 index d0be29bc2e..0000000000 --- a/code/renderergl1/tr_mesh.c +++ /dev/null @@ -1,412 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_mesh.c: triangle model functions - -#include "tr_local.h" - -static float ProjectRadius( float r, vec3_t location ) -{ - float pr; - float dist; - float c; - vec3_t p; - float projected[4]; - - c = DotProduct( tr.viewParms.or.axis[0], tr.viewParms.or.origin ); - dist = DotProduct( tr.viewParms.or.axis[0], location ) - c; - - if ( dist <= 0 ) - return 0; - - p[0] = 0; - p[1] = fabs( r ); - p[2] = -dist; - - projected[0] = p[0] * tr.viewParms.projectionMatrix[0] + - p[1] * tr.viewParms.projectionMatrix[4] + - p[2] * tr.viewParms.projectionMatrix[8] + - tr.viewParms.projectionMatrix[12]; - - projected[1] = p[0] * tr.viewParms.projectionMatrix[1] + - p[1] * tr.viewParms.projectionMatrix[5] + - p[2] * tr.viewParms.projectionMatrix[9] + - tr.viewParms.projectionMatrix[13]; - - projected[2] = p[0] * tr.viewParms.projectionMatrix[2] + - p[1] * tr.viewParms.projectionMatrix[6] + - p[2] * tr.viewParms.projectionMatrix[10] + - tr.viewParms.projectionMatrix[14]; - - projected[3] = p[0] * tr.viewParms.projectionMatrix[3] + - p[1] * tr.viewParms.projectionMatrix[7] + - p[2] * tr.viewParms.projectionMatrix[11] + - tr.viewParms.projectionMatrix[15]; - - - pr = projected[1] / projected[3]; - - if ( pr > 1.0f ) - pr = 1.0f; - - return pr; -} - -/* -============= -R_CullModel -============= -*/ -static int R_CullModel( md3Header_t *header, trRefEntity_t *ent ) { - vec3_t bounds[2]; - md3Frame_t *oldFrame, *newFrame; - int i; - - // compute frame pointers - newFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame; - oldFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe; - - // cull bounding sphere ONLY if this is not an upscaled entity - if ( !ent->e.nonNormalizedAxes ) - { - if ( ent->e.frame == ent->e.oldframe ) - { - switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) - { - case CULL_OUT: - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - - case CULL_IN: - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - - case CULL_CLIP: - tr.pc.c_sphere_cull_md3_clip++; - break; - } - } - else - { - int sphereCull, sphereCullB; - - sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); - if ( newFrame == oldFrame ) { - sphereCullB = sphereCull; - } else { - sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); - } - - if ( sphereCull == sphereCullB ) - { - if ( sphereCull == CULL_OUT ) - { - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - } - else if ( sphereCull == CULL_IN ) - { - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - } - else - { - tr.pc.c_sphere_cull_md3_clip++; - } - } - } - } - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; - bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - - -/* -================= -R_ComputeLOD - -================= -*/ -int R_ComputeLOD( trRefEntity_t *ent ) { - float radius; - float flod, lodscale; - float projectedRadius; - md3Frame_t *frame; - mdrHeader_t *mdr; - mdrFrame_t *mdrframe; - int lod; - - if ( tr.currentModel->numLods < 2 ) - { - // model has only 1 LOD level, skip computations and bias - lod = 0; - } - else - { - // multiple LODs exist, so compute projected bounding sphere - // and use that as a criteria for selecting LOD - - if(tr.currentModel->type == MOD_MDR) - { - int frameSize; - mdr = (mdrHeader_t *) tr.currentModel->modelData; - frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]); - - mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame); - - radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]); - } - else - { - frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames ); - - frame += ent->e.frame; - - radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] ); - } - - if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) - { - lodscale = r_lodscale->value; - if (lodscale > 20) lodscale = 20; - flod = 1.0f - projectedRadius * lodscale; - } - else - { - // object intersects near view plane, e.g. view weapon - flod = 0; - } - - flod *= tr.currentModel->numLods; - lod = ri.ftol(flod); - - if ( lod < 0 ) - { - lod = 0; - } - else if ( lod >= tr.currentModel->numLods ) - { - lod = tr.currentModel->numLods - 1; - } - } - - lod += r_lodbias->integer; - - if ( lod >= tr.currentModel->numLods ) - lod = tr.currentModel->numLods - 1; - if ( lod < 0 ) - lod = 0; - - return lod; -} - -/* -================= -R_ComputeFogNum - -================= -*/ -int R_ComputeFogNum( md3Header_t *header, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - md3Frame_t *md3Frame; - vec3_t localOrigin; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - // FIXME: non-normalized axis issues - md3Frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame; - VectorAdd( ent->e.origin, md3Frame->localOrigin, localOrigin ); - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - md3Frame->radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + md3Frame->radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -================= -R_AddMD3Surfaces - -================= -*/ -void R_AddMD3Surfaces( trRefEntity_t *ent ) { - int i; - md3Header_t *header = NULL; - md3Surface_t *surface = NULL; - md3Shader_t *md3Shader = NULL; - shader_t *shader = NULL; - int cull; - int lod; - int fogNum; - qboolean personalModel; - - // don't add third_person objects if not in a portal - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) { - ent->e.frame %= tr.currentModel->md3[0]->numFrames; - ent->e.oldframe %= tr.currentModel->md3[0]->numFrames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ( (ent->e.frame >= tr.currentModel->md3[0]->numFrames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= tr.currentModel->md3[0]->numFrames) - || (ent->e.oldframe < 0) ) { - ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, - tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // compute LOD - // - lod = R_ComputeLOD( ent ); - - header = tr.currentModel->md3[lod]; - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_CullModel ( header, ent ); - if ( cull == CULL_OUT ) { - return; - } - - // - // set up lighting now that we know we aren't culled - // - if ( !personalModel || r_shadows->integer > 1 ) { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // - // see if we are in a fog volume - // - fogNum = R_ComputeFogNum( header, ent ); - - // - // draw all surfaces - // - surface = (md3Surface_t *)( (byte *)header + header->ofsSurfaces ); - for ( i = 0 ; i < header->numSurfaces ; i++ ) { - - if ( ent->e.customShader ) { - shader = R_GetShaderByHandle( ent->e.customShader ); - } else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) { - skin_t *skin; - int j; - - skin = R_GetSkinByHandle( ent->e.customSkin ); - - // match the surface name to something in the skin file - shader = tr.defaultShader; - for ( j = 0 ; j < skin->numSurfaces ; j++ ) { - // the names have both been lowercased - if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) { - shader = skin->surfaces[j]->shader; - break; - } - } - if (shader == tr.defaultShader) { - ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name); - } - else if (shader->defaultShader) { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name); - } - } else if ( surface->numShaders <= 0 ) { - shader = tr.defaultShader; - } else { - md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders ); - md3Shader += ent->e.skinNum % surface->numShaders; - shader = tr.shaders[ md3Shader->shaderIndex ]; - } - - - // we will add shadows even if the main object isn't visible in the view - - // stencil shadows can't do personal models unless I polyhedron clip - if ( !personalModel - && r_shadows->integer == 2 - && fogNum == 0 - && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse ); - } - - // projection shadows work fine with personal models - if ( r_shadows->integer == 3 - && fogNum == 0 - && (ent->e.renderfx & RF_SHADOW_PLANE ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse ); - } - - // don't add third_person objects if not viewing through a portal - if ( !personalModel ) { - R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse ); - } - - surface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd ); - } - -} - diff --git a/code/renderergl1/tr_model.c b/code/renderergl1/tr_model.c deleted file mode 100644 index a3f91aeee1..0000000000 --- a/code/renderergl1/tr_model.c +++ /dev/null @@ -1,1127 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_models.c -- model loading and caching - -#include "tr_local.h" - -#define LL(x) x=LittleLong(x) - -static qboolean R_LoadMD3(model_t *mod, int lod, void *buffer, const char *name ); -static qboolean R_LoadMDR(model_t *mod, void *buffer, int filesize, const char *name ); - -/* -==================== -R_RegisterMD3 -==================== -*/ -qhandle_t R_RegisterMD3(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - int lod; - int ident; - qboolean loaded = qfalse; - int numLoaded; - char filename[MAX_QPATH], namebuf[MAX_QPATH+20]; - char *fext, defex[] = "md3"; - - numLoaded = 0; - - strcpy(filename, name); - - fext = strchr(filename, '.'); - if(!fext) - fext = defex; - else - { - *fext = '\0'; - fext++; - } - - for (lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod--) - { - if(lod) - Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext); - else - Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext); - - ri.FS_ReadFile( namebuf, &buf.v ); - if(!buf.u) - continue; - - ident = LittleLong(* (unsigned *) buf.u); - if (ident == MD3_IDENT) - loaded = R_LoadMD3(mod, lod, buf.u, name); - else - ri.Printf(PRINT_WARNING,"R_RegisterMD3: unknown fileid for %s\n", name); - - ri.FS_FreeFile(buf.v); - - if(loaded) - { - mod->numLods++; - numLoaded++; - } - else - break; - } - - if(numLoaded) - { - // duplicate into higher lod spots that weren't - // loaded, in case the user changes r_lodbias on the fly - for(lod--; lod >= 0; lod--) - { - mod->numLods++; - mod->md3[lod] = mod->md3[lod + 1]; - } - - return mod->index; - } - -#ifdef _DEBUG - ri.Printf(PRINT_WARNING,"R_RegisterMD3: couldn't load %s\n", name); -#endif - - mod->type = MOD_BAD; - return 0; -} - -/* -==================== -R_RegisterMDR -==================== -*/ -qhandle_t R_RegisterMDR(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - int ident; - qboolean loaded = qfalse; - int filesize; - - filesize = ri.FS_ReadFile(name, (void **) &buf.v); - if(!buf.u) - { - mod->type = MOD_BAD; - return 0; - } - - ident = LittleLong(*(unsigned *)buf.u); - if(ident == MDR_IDENT) - loaded = R_LoadMDR(mod, buf.u, filesize, name); - - ri.FS_FreeFile (buf.v); - - if(!loaded) - { - ri.Printf(PRINT_WARNING,"R_RegisterMDR: couldn't load mdr file %s\n", name); - mod->type = MOD_BAD; - return 0; - } - - return mod->index; -} - -/* -==================== -R_RegisterIQM -==================== -*/ -qhandle_t R_RegisterIQM(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - qboolean loaded = qfalse; - int filesize; - - filesize = ri.FS_ReadFile(name, (void **) &buf.v); - if(!buf.u) - { - mod->type = MOD_BAD; - return 0; - } - - loaded = R_LoadIQM(mod, buf.u, filesize, name); - - ri.FS_FreeFile (buf.v); - - if(!loaded) - { - ri.Printf(PRINT_WARNING,"R_RegisterIQM: couldn't load iqm file %s\n", name); - mod->type = MOD_BAD; - return 0; - } - - return mod->index; -} - - -typedef struct -{ - char *ext; - qhandle_t (*ModelLoader)( const char *, model_t * ); -} modelExtToLoaderMap_t; - -// Note that the ordering indicates the order of preference used -// when there are multiple models of different formats available -static modelExtToLoaderMap_t modelLoaders[ ] = -{ - { "iqm", R_RegisterIQM }, - { "mdr", R_RegisterMDR }, - { "md3", R_RegisterMD3 } -}; - -static int numModelLoaders = ARRAY_LEN(modelLoaders); - -//=============================================================================== - -/* -** R_GetModelByHandle -*/ -model_t *R_GetModelByHandle( qhandle_t index ) { - model_t *mod; - - // out of range gets the defualt model - if ( index < 1 || index >= tr.numModels ) { - return tr.models[0]; - } - - mod = tr.models[index]; - - return mod; -} - -//=============================================================================== - -/* -** R_AllocModel -*/ -model_t *R_AllocModel( void ) { - model_t *mod; - - if ( tr.numModels == MAX_MOD_KNOWN ) { - return NULL; - } - - mod = ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low ); - mod->index = tr.numModels; - tr.models[tr.numModels] = mod; - tr.numModels++; - - return mod; -} - -/* -==================== -RE_RegisterModel - -Loads in a model for the given name - -Zero will be returned if the model fails to load. -An entry will be retained for failed models as an -optimization to prevent disk rescanning if they are -asked for again. -==================== -*/ -qhandle_t RE_RegisterModel( const char *name ) { - model_t *mod; - qhandle_t hModel; - qboolean orgNameFailed = qfalse; - int orgLoader = -1; - int i; - char localName[ MAX_QPATH ]; - const char *ext; - char altName[ MAX_QPATH ]; - - if ( !name || !name[0] ) { - ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" ); - return 0; - } - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Model name exceeds MAX_QPATH\n" ); - return 0; - } - - // - // search the currently loaded models - // - for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) { - mod = tr.models[hModel]; - if ( !strcmp( mod->name, name ) ) { - if( mod->type == MOD_BAD ) { - return 0; - } - return hModel; - } - } - - // allocate a new model_t - - if ( ( mod = R_AllocModel() ) == NULL ) { - ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name); - return 0; - } - - // only set the name after the model has been successfully loaded - Q_strncpyz( mod->name, name, sizeof( mod->name ) ); - - - R_IssuePendingRenderCommands(); - - mod->type = MOD_BAD; - mod->numLods = 0; - - // - // load the files - // - Q_strncpyz( localName, name, MAX_QPATH ); - - ext = COM_GetExtension( localName ); - - if( *ext ) - { - // Look for the correct loader and use it - for( i = 0; i < numModelLoaders; i++ ) - { - if( !Q_stricmp( ext, modelLoaders[ i ].ext ) ) - { - // Load - hModel = modelLoaders[ i ].ModelLoader( localName, mod ); - break; - } - } - - // A loader was found - if( i < numModelLoaders ) - { - if( !hModel ) - { - // Loader failed, most likely because the file isn't there; - // try again without the extension - orgNameFailed = qtrue; - orgLoader = i; - COM_StripExtension( name, localName, MAX_QPATH ); - } - else - { - // Something loaded - return mod->index; - } - } - } - - // Try and find a suitable match using all - // the model formats supported - for( i = 0; i < numModelLoaders; i++ ) - { - if (i == orgLoader) - continue; - - Com_sprintf( altName, sizeof (altName), "%s.%s", localName, modelLoaders[ i ].ext ); - - // Load - hModel = modelLoaders[ i ].ModelLoader( altName, mod ); - - if( hModel ) - { - if( orgNameFailed ) - { - ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n", - name, altName ); - } - - break; - } - } - - return hModel; -} - -/* -================= -R_LoadMD3 -================= -*/ -static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) { - int i, j; - md3Header_t *pinmodel; - md3Frame_t *frame; - md3Surface_t *surf; - md3Shader_t *shader; - md3Triangle_t *tri; - md3St_t *st; - md3XyzNormal_t *xyz; - md3Tag_t *tag; - int version; - int size; - - pinmodel = (md3Header_t *)buffer; - - version = LittleLong (pinmodel->version); - if (version != MD3_VERSION) { - ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n", - mod_name, version, MD3_VERSION); - return qfalse; - } - - mod->type = MOD_MESH; - size = LittleLong(pinmodel->ofsEnd); - mod->dataSize += size; - mod->md3[lod] = ri.Hunk_Alloc( size, h_low ); - - Com_Memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) ); - - LL(mod->md3[lod]->ident); - LL(mod->md3[lod]->version); - LL(mod->md3[lod]->numFrames); - LL(mod->md3[lod]->numTags); - LL(mod->md3[lod]->numSurfaces); - LL(mod->md3[lod]->ofsFrames); - LL(mod->md3[lod]->ofsTags); - LL(mod->md3[lod]->ofsSurfaces); - LL(mod->md3[lod]->ofsEnd); - - if ( mod->md3[lod]->numFrames < 1 ) { - ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name ); - return qfalse; - } - - // swap all the frames - frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames ); - for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) { - frame->radius = LittleFloat( frame->radius ); - for ( j = 0 ; j < 3 ; j++ ) { - frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] ); - frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] ); - frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] ); - } - } - - // swap all the tags - tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags ); - for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) { - for ( j = 0 ; j < 3 ; j++ ) { - tag->origin[j] = LittleFloat( tag->origin[j] ); - tag->axis[0][j] = LittleFloat( tag->axis[0][j] ); - tag->axis[1][j] = LittleFloat( tag->axis[1][j] ); - tag->axis[2][j] = LittleFloat( tag->axis[2][j] ); - } - } - - // swap all the surfaces - surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces ); - for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) { - - LL(surf->ident); - LL(surf->flags); - LL(surf->numFrames); - LL(surf->numShaders); - LL(surf->numTriangles); - LL(surf->ofsTriangles); - LL(surf->numVerts); - LL(surf->ofsShaders); - LL(surf->ofsSt); - LL(surf->ofsXyzNormals); - LL(surf->ofsEnd); - - if ( surf->numVerts >= SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", - surf->numVerts ); - return qfalse; - } - if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", - surf->numTriangles ); - return qfalse; - } - - // change to surface identifier - surf->ident = SF_MD3; - - // lowercase the surface name so skin compares are faster - Q_strlwr( surf->name ); - - // strip off a trailing _1 or _2 - // this is a crutch for q3data being a mess - j = strlen( surf->name ); - if ( j > 2 && surf->name[j-2] == '_' ) { - surf->name[j-2] = 0; - } - - // register the shaders - shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders ); - for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) { - shader_t *sh; - - sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue ); - if ( sh->defaultShader ) { - shader->shaderIndex = 0; - } else { - shader->shaderIndex = sh->index; - } - } - - // swap all the triangles - tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles ); - for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { - LL(tri->indexes[0]); - LL(tri->indexes[1]); - LL(tri->indexes[2]); - } - - // swap all the ST - st = (md3St_t *) ( (byte *)surf + surf->ofsSt ); - for ( j = 0 ; j < surf->numVerts ; j++, st++ ) { - st->st[0] = LittleFloat( st->st[0] ); - st->st[1] = LittleFloat( st->st[1] ); - } - - // swap all the XyzNormals - xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals ); - for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ ) - { - xyz->xyz[0] = LittleShort( xyz->xyz[0] ); - xyz->xyz[1] = LittleShort( xyz->xyz[1] ); - xyz->xyz[2] = LittleShort( xyz->xyz[2] ); - - xyz->normal = LittleShort( xyz->normal ); - } - - - // find the next surface - surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd ); - } - - return qtrue; -} - - - -/* -================= -R_LoadMDR -================= -*/ -static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name ) -{ - int i, j, k, l; - mdrHeader_t *pinmodel, *mdr; - mdrFrame_t *frame; - mdrLOD_t *lod, *curlod; - mdrSurface_t *surf, *cursurf; - mdrTriangle_t *tri, *curtri; - mdrVertex_t *v, *curv; - mdrWeight_t *weight, *curweight; - mdrTag_t *tag, *curtag; - int size; - shader_t *sh; - - pinmodel = (mdrHeader_t *)buffer; - - pinmodel->version = LittleLong(pinmodel->version); - if (pinmodel->version != MDR_VERSION) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION); - return qfalse; - } - - size = LittleLong(pinmodel->ofsEnd); - - if(size > filesize) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name); - return qfalse; - } - - mod->type = MOD_MDR; - - LL(pinmodel->numFrames); - LL(pinmodel->numBones); - LL(pinmodel->ofsFrames); - - // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame - // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target mdr. - if(pinmodel->ofsFrames < 0) - { - // mdrFrame_t is larger than mdrCompFrame_t: - size += pinmodel->numFrames * sizeof(frame->name); - // now add enough space for the uncompressed bones. - size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t))); - } - - // simple bounds check - if(pinmodel->numBones < 0 || - sizeof(*mdr) + pinmodel->numFrames * (sizeof(*frame) + (pinmodel->numBones - 1) * sizeof(*frame->bones)) > size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - mod->dataSize += size; - mod->modelData = mdr = ri.Hunk_Alloc( size, h_low ); - - // Copy all the values over from the file and fix endian issues in the process, if necessary. - - mdr->ident = LittleLong(pinmodel->ident); - mdr->version = pinmodel->version; // Don't need to swap byte order on this one, we already did above. - Q_strncpyz(mdr->name, pinmodel->name, sizeof(mdr->name)); - mdr->numFrames = pinmodel->numFrames; - mdr->numBones = pinmodel->numBones; - mdr->numLODs = LittleLong(pinmodel->numLODs); - mdr->numTags = LittleLong(pinmodel->numTags); - // We don't care about the other offset values, we'll generate them ourselves while loading. - - mod->numLods = mdr->numLODs; - - if ( mdr->numFrames < 1 ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name); - return qfalse; - } - - /* The first frame will be put into the first free space after the header */ - frame = (mdrFrame_t *)(mdr + 1); - mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr); - - if (pinmodel->ofsFrames < 0) - { - mdrCompFrame_t *cframe; - - // compressed model... - cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames); - - for(i = 0; i < mdr->numFrames; i++) - { - for(j = 0; j < 3; j++) - { - frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]); - frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]); - frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]); - } - - frame->radius = LittleFloat(cframe->radius); - frame->name[0] = '\0'; // No name supplied in the compressed version. - - for(j = 0; j < mdr->numBones; j++) - { - for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++) - { - // Do swapping for the uncompressing functions. They seem to use shorts - // values only, so I assume this will work. Never tested it on other - // platforms, though. - - ((unsigned short *)(cframe->bones[j].Comp))[k] = - LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] ); - } - - /* Now do the actual uncompressing */ - MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp); - } - - // Next Frame... - cframe = (mdrCompFrame_t *) &cframe->bones[j]; - frame = (mdrFrame_t *) &frame->bones[j]; - } - } - else - { - mdrFrame_t *curframe; - - // uncompressed model... - // - - curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames); - - // swap all the frames - for ( i = 0 ; i < mdr->numFrames ; i++) - { - for(j = 0; j < 3; j++) - { - frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]); - frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]); - frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]); - } - - frame->radius = LittleFloat(curframe->radius); - Q_strncpyz(frame->name, curframe->name, sizeof(frame->name)); - - for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++) - { - ((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] ); - } - - curframe = (mdrFrame_t *) &curframe->bones[mdr->numBones]; - frame = (mdrFrame_t *) &frame->bones[mdr->numBones]; - } - } - - // frame should now point to the first free address after all frames. - lod = (mdrLOD_t *) frame; - mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr); - - curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs)); - - // swap all the LOD's - for ( l = 0 ; l < mdr->numLODs ; l++) - { - // simple bounds check - if((byte *) (lod + 1) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - lod->numSurfaces = LittleLong(curlod->numSurfaces); - - // swap all the surfaces - surf = (mdrSurface_t *) (lod + 1); - lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod); - cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces)); - - for ( i = 0 ; i < lod->numSurfaces ; i++) - { - // simple bounds check - if((byte *) (surf + 1) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - // first do some copying stuff - - surf->ident = SF_MDR; - Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name)); - Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader)); - - surf->ofsHeader = (byte *) mdr - (byte *) surf; - - surf->numVerts = LittleLong(cursurf->numVerts); - surf->numTriangles = LittleLong(cursurf->numTriangles); - // numBoneReferences and BoneReferences generally seem to be unused - - // now do the checks that may fail. - if ( surf->numVerts >= SHADER_MAX_VERTEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", - surf->numVerts ); - return qfalse; - } - if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", - surf->numTriangles ); - return qfalse; - } - // lowercase the surface name so skin compares are faster - Q_strlwr( surf->name ); - - // register the shaders - sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue); - if ( sh->defaultShader ) { - surf->shaderIndex = 0; - } else { - surf->shaderIndex = sh->index; - } - - // now copy the vertexes. - v = (mdrVertex_t *) (surf + 1); - surf->ofsVerts = (int)((byte *) v - (byte *) surf); - curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts)); - - for(j = 0; j < surf->numVerts; j++) - { - LL(curv->numWeights); - - // simple bounds check - if(curv->numWeights < 0 || (byte *) (v + 1) + (curv->numWeights - 1) * sizeof(*weight) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - v->normal[0] = LittleFloat(curv->normal[0]); - v->normal[1] = LittleFloat(curv->normal[1]); - v->normal[2] = LittleFloat(curv->normal[2]); - - v->texCoords[0] = LittleFloat(curv->texCoords[0]); - v->texCoords[1] = LittleFloat(curv->texCoords[1]); - - v->numWeights = curv->numWeights; - weight = &v->weights[0]; - curweight = &curv->weights[0]; - - // Now copy all the weights - for(k = 0; k < v->numWeights; k++) - { - weight->boneIndex = LittleLong(curweight->boneIndex); - weight->boneWeight = LittleFloat(curweight->boneWeight); - - weight->offset[0] = LittleFloat(curweight->offset[0]); - weight->offset[1] = LittleFloat(curweight->offset[1]); - weight->offset[2] = LittleFloat(curweight->offset[2]); - - weight++; - curweight++; - } - - v = (mdrVertex_t *) weight; - curv = (mdrVertex_t *) curweight; - } - - // we know the offset to the triangles now: - tri = (mdrTriangle_t *) v; - surf->ofsTriangles = (int)((byte *) tri - (byte *) surf); - curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles)); - - // simple bounds check - if(surf->numTriangles < 0 || (byte *) (tri + surf->numTriangles) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - for(j = 0; j < surf->numTriangles; j++) - { - tri->indexes[0] = LittleLong(curtri->indexes[0]); - tri->indexes[1] = LittleLong(curtri->indexes[1]); - tri->indexes[2] = LittleLong(curtri->indexes[2]); - - tri++; - curtri++; - } - - // tri now points to the end of the surface. - surf->ofsEnd = (byte *) tri - (byte *) surf; - surf = (mdrSurface_t *) tri; - - // find the next surface. - cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd)); - } - - // surf points to the next lod now. - lod->ofsEnd = (int)((byte *) surf - (byte *) lod); - lod = (mdrLOD_t *) surf; - - // find the next LOD. - curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd)); - } - - // lod points to the first tag now, so update the offset too. - tag = (mdrTag_t *) lod; - mdr->ofsTags = (int)((byte *) tag - (byte *) mdr); - curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags)); - - // simple bounds check - if(mdr->numTags < 0 || (byte *) (tag + mdr->numTags) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - for (i = 0 ; i < mdr->numTags ; i++) - { - tag->boneIndex = LittleLong(curtag->boneIndex); - Q_strncpyz(tag->name, curtag->name, sizeof(tag->name)); - - tag++; - curtag++; - } - - // And finally we know the real offset to the end. - mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr); - - // phew! we're done. - - return qtrue; -} - - - -//============================================================================= - -/* -** RE_BeginRegistration -*/ -void RE_BeginRegistration( glconfig_t *glconfigOut ) { - - R_Init(); - - *glconfigOut = glConfig; - - R_IssuePendingRenderCommands(); - - tr.viewCluster = -1; // force markleafs to regenerate - R_ClearFlares(); - RE_ClearScene(); - - tr.registered = qtrue; -} - -//============================================================================= - -/* -=============== -R_ModelInit -=============== -*/ -void R_ModelInit( void ) { - model_t *mod; - - // leave a space for NULL model - tr.numModels = 0; - - mod = R_AllocModel(); - mod->type = MOD_BAD; -} - - -/* -================ -R_Modellist_f -================ -*/ -void R_Modellist_f( void ) { - int i, j; - model_t *mod; - int total; - int lods; - - total = 0; - for ( i = 1 ; i < tr.numModels; i++ ) { - mod = tr.models[i]; - lods = 1; - for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) { - if ( mod->md3[j] && mod->md3[j] != mod->md3[j-1] ) { - lods++; - } - } - ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name ); - total += mod->dataSize; - } - ri.Printf( PRINT_ALL, "%8i : Total models\n", total ); - -#if 0 // not working right with new hunk - if ( tr.world ) { - ri.Printf( PRINT_ALL, "\n%8i : %s\n", tr.world->dataSize, tr.world->name ); - } -#endif -} - - -//============================================================================= - - -/* -================ -R_GetTag -================ -*/ -static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) { - md3Tag_t *tag; - int i; - - if ( frame >= mod->numFrames ) { - // it is possible to have a bad frame while changing models, so don't error - frame = mod->numFrames - 1; - } - - tag = (md3Tag_t *)((byte *)mod + mod->ofsTags) + frame * mod->numTags; - for ( i = 0 ; i < mod->numTags ; i++, tag++ ) { - if ( !strcmp( tag->name, tagName ) ) { - return tag; // found it - } - } - - return NULL; -} - -void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t * dest) -{ - int i, j, k; - int frameSize; - mdrFrame_t *frame; - mdrTag_t *tag; - - if ( framenum >= mod->numFrames ) - { - // it is possible to have a bad frame while changing models, so don't error - framenum = mod->numFrames - 1; - } - - tag = (mdrTag_t *)((byte *)mod + mod->ofsTags); - for ( i = 0 ; i < mod->numTags ; i++, tag++ ) - { - if ( !strcmp( tag->name, tagName ) ) - { - Q_strncpyz(dest->name, tag->name, sizeof(dest->name)); - - // uncompressed model... - // - frameSize = (intptr_t)( &((mdrFrame_t *)0)->bones[ mod->numBones ] ); - frame = (mdrFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize ); - - for (j = 0; j < 3; j++) - { - for (k = 0; k < 3; k++) - dest->axis[j][k]=frame->bones[tag->boneIndex].matrix[k][j]; - } - - dest->origin[0]=frame->bones[tag->boneIndex].matrix[0][3]; - dest->origin[1]=frame->bones[tag->boneIndex].matrix[1][3]; - dest->origin[2]=frame->bones[tag->boneIndex].matrix[2][3]; - - return; - } - } - - AxisClear( dest->axis ); - VectorClear( dest->origin ); - strcpy(dest->name,""); -} - -/* -================ -R_LerpTag -================ -*/ -int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, - float frac, const char *tagName ) { - md3Tag_t *start, *end; - md3Tag_t start_space, end_space; - int i; - float frontLerp, backLerp; - model_t *model; - - model = R_GetModelByHandle( handle ); - if ( !model->md3[0] ) - { - if(model->type == MOD_MDR) - { - start = &start_space; - end = &end_space; - R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, start); - R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, end); - } - else if( model->type == MOD_IQM ) { - return R_IQMLerpTag( tag, model->modelData, - startFrame, endFrame, - frac, tagName ); - } else { - - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - - } - } - else - { - start = R_GetTag( model->md3[0], startFrame, tagName ); - end = R_GetTag( model->md3[0], endFrame, tagName ); - if ( !start || !end ) { - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - } - } - - frontLerp = frac; - backLerp = 1.0f - frac; - - for ( i = 0 ; i < 3 ; i++ ) { - tag->origin[i] = start->origin[i] * backLerp + end->origin[i] * frontLerp; - tag->axis[0][i] = start->axis[0][i] * backLerp + end->axis[0][i] * frontLerp; - tag->axis[1][i] = start->axis[1][i] * backLerp + end->axis[1][i] * frontLerp; - tag->axis[2][i] = start->axis[2][i] * backLerp + end->axis[2][i] * frontLerp; - } - VectorNormalize( tag->axis[0] ); - VectorNormalize( tag->axis[1] ); - VectorNormalize( tag->axis[2] ); - return qtrue; -} - - -/* -==================== -R_ModelBounds -==================== -*/ -void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { - model_t *model; - - model = R_GetModelByHandle( handle ); - - if(model->type == MOD_BRUSH) { - VectorCopy( model->bmodel->bounds[0], mins ); - VectorCopy( model->bmodel->bounds[1], maxs ); - - return; - } else if (model->type == MOD_MESH) { - md3Header_t *header; - md3Frame_t *frame; - - header = model->md3[0]; - frame = (md3Frame_t *) ((byte *)header + header->ofsFrames); - - VectorCopy( frame->bounds[0], mins ); - VectorCopy( frame->bounds[1], maxs ); - - return; - } else if (model->type == MOD_MDR) { - mdrHeader_t *header; - mdrFrame_t *frame; - - header = (mdrHeader_t *)model->modelData; - frame = (mdrFrame_t *) ((byte *)header + header->ofsFrames); - - VectorCopy( frame->bounds[0], mins ); - VectorCopy( frame->bounds[1], maxs ); - - return; - } else if(model->type == MOD_IQM) { - iqmData_t *iqmData; - - iqmData = model->modelData; - - if(iqmData->bounds) - { - VectorCopy(iqmData->bounds, mins); - VectorCopy(iqmData->bounds + 3, maxs); - return; - } - } - - VectorClear( mins ); - VectorClear( maxs ); -} diff --git a/code/renderergl1/tr_model_iqm.c b/code/renderergl1/tr_model_iqm.c deleted file mode 100644 index 0f99f1605c..0000000000 --- a/code/renderergl1/tr_model_iqm.c +++ /dev/null @@ -1,1185 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2011 Thilo Schulz -Copyright (C) 2011 Matthias Bentrup - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -#define LL(x) x=LittleLong(x) - -// 3x4 identity matrix -static float identityMatrix[12] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0 -}; - -static qboolean IQM_CheckRange( iqmHeader_t *header, int offset, - int count,int size ) { - // return true if the range specified by offset, count and size - // doesn't fit into the file - return ( count <= 0 || - offset < 0 || - offset > header->filesize || - offset + count * size < 0 || - offset + count * size > header->filesize ); -} -// "multiply" 3x4 matrices, these are assumed to be the top 3 rows -// of a 4x4 matrix with the last row = (0 0 0 1) -static void Matrix34Multiply( float *a, float *b, float *out ) { - out[ 0] = a[0] * b[0] + a[1] * b[4] + a[ 2] * b[ 8]; - out[ 1] = a[0] * b[1] + a[1] * b[5] + a[ 2] * b[ 9]; - out[ 2] = a[0] * b[2] + a[1] * b[6] + a[ 2] * b[10]; - out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; - out[ 4] = a[4] * b[0] + a[5] * b[4] + a[ 6] * b[ 8]; - out[ 5] = a[4] * b[1] + a[5] * b[5] + a[ 6] * b[ 9]; - out[ 6] = a[4] * b[2] + a[5] * b[6] + a[ 6] * b[10]; - out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; - out[ 8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[ 8]; - out[ 9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[ 9]; - out[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10]; - out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; -} -static void Matrix34Multiply_OnlySetOrigin( float *a, float *b, float *out ) { - out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; - out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; - out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; -} -static void InterpolateMatrix( float *a, float *b, float lerp, float *mat ) { - float unLerp = 1.0f - lerp; - - mat[ 0] = a[ 0] * unLerp + b[ 0] * lerp; - mat[ 1] = a[ 1] * unLerp + b[ 1] * lerp; - mat[ 2] = a[ 2] * unLerp + b[ 2] * lerp; - mat[ 3] = a[ 3] * unLerp + b[ 3] * lerp; - mat[ 4] = a[ 4] * unLerp + b[ 4] * lerp; - mat[ 5] = a[ 5] * unLerp + b[ 5] * lerp; - mat[ 6] = a[ 6] * unLerp + b[ 6] * lerp; - mat[ 7] = a[ 7] * unLerp + b[ 7] * lerp; - mat[ 8] = a[ 8] * unLerp + b[ 8] * lerp; - mat[ 9] = a[ 9] * unLerp + b[ 9] * lerp; - mat[10] = a[10] * unLerp + b[10] * lerp; - mat[11] = a[11] * unLerp + b[11] * lerp; -} -static void JointToMatrix( vec4_t rot, vec3_t scale, vec3_t trans, - float *mat ) { - float xx = 2.0f * rot[0] * rot[0]; - float yy = 2.0f * rot[1] * rot[1]; - float zz = 2.0f * rot[2] * rot[2]; - float xy = 2.0f * rot[0] * rot[1]; - float xz = 2.0f * rot[0] * rot[2]; - float yz = 2.0f * rot[1] * rot[2]; - float wx = 2.0f * rot[3] * rot[0]; - float wy = 2.0f * rot[3] * rot[1]; - float wz = 2.0f * rot[3] * rot[2]; - - mat[ 0] = scale[0] * (1.0f - (yy + zz)); - mat[ 1] = scale[0] * (xy - wz); - mat[ 2] = scale[0] * (xz + wy); - mat[ 3] = trans[0]; - mat[ 4] = scale[1] * (xy + wz); - mat[ 5] = scale[1] * (1.0f - (xx + zz)); - mat[ 6] = scale[1] * (yz - wx); - mat[ 7] = trans[1]; - mat[ 8] = scale[2] * (xz - wy); - mat[ 9] = scale[2] * (yz + wx); - mat[10] = scale[2] * (1.0f - (xx + yy)); - mat[11] = trans[2]; -} -static void Matrix34Invert( float *inMat, float *outMat ) -{ - vec3_t trans; - float invSqrLen, *v; - - outMat[ 0] = inMat[ 0]; outMat[ 1] = inMat[ 4]; outMat[ 2] = inMat[ 8]; - outMat[ 4] = inMat[ 1]; outMat[ 5] = inMat[ 5]; outMat[ 6] = inMat[ 9]; - outMat[ 8] = inMat[ 2]; outMat[ 9] = inMat[ 6]; outMat[10] = inMat[10]; - - v = outMat + 0; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - v = outMat + 4; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - v = outMat + 8; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - - trans[0] = inMat[ 3]; - trans[1] = inMat[ 7]; - trans[2] = inMat[11]; - - outMat[ 3] = -DotProduct(outMat + 0, trans); - outMat[ 7] = -DotProduct(outMat + 4, trans); - outMat[11] = -DotProduct(outMat + 8, trans); -} - -/* -================= -R_LoadIQM - -Load an IQM model and compute the joint matrices for every frame. -================= -*/ -qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_name ) { - iqmHeader_t *header; - iqmVertexArray_t *vertexarray; - iqmTriangle_t *triangle; - iqmMesh_t *mesh; - iqmJoint_t *joint; - iqmPose_t *pose; - iqmBounds_t *bounds; - unsigned short *framedata; - char *str; - int i, j; - float jointInvMats[IQM_MAX_JOINTS * 12]; - float *mat, *matInv; - size_t size, joint_names; - iqmData_t *iqmData; - srfIQModel_t *surface; - char meshName[MAX_QPATH]; - byte blendIndexesType, blendWeightsType; - - if( filesize < sizeof(iqmHeader_t) ) { - return qfalse; - } - - header = (iqmHeader_t *)buffer; - if( Q_strncmp( header->magic, IQM_MAGIC, sizeof(header->magic) ) ) { - return qfalse; - } - - LL( header->version ); - if( header->version != IQM_VERSION ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s is a unsupported IQM version (%d), only version %d is supported.\n", - mod_name, header->version, IQM_VERSION); - return qfalse; - } - - LL( header->filesize ); - if( header->filesize > filesize || header->filesize > 16<<20 ) { - return qfalse; - } - - LL( header->flags ); - LL( header->num_text ); - LL( header->ofs_text ); - LL( header->num_meshes ); - LL( header->ofs_meshes ); - LL( header->num_vertexarrays ); - LL( header->num_vertexes ); - LL( header->ofs_vertexarrays ); - LL( header->num_triangles ); - LL( header->ofs_triangles ); - LL( header->ofs_adjacency ); - LL( header->num_joints ); - LL( header->ofs_joints ); - LL( header->num_poses ); - LL( header->ofs_poses ); - LL( header->num_anims ); - LL( header->ofs_anims ); - LL( header->num_frames ); - LL( header->num_framechannels ); - LL( header->ofs_frames ); - LL( header->ofs_bounds ); - LL( header->num_comment ); - LL( header->ofs_comment ); - LL( header->num_extensions ); - LL( header->ofs_extensions ); - - // check ioq3 joint limit - if ( header->num_joints > IQM_MAX_JOINTS ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %d joints (%d).\n", - mod_name, IQM_MAX_JOINTS, header->num_joints); - return qfalse; - } - - blendIndexesType = blendWeightsType = IQM_UBYTE; - - // check and swap vertex arrays - if( IQM_CheckRange( header, header->ofs_vertexarrays, - header->num_vertexarrays, - sizeof(iqmVertexArray_t) ) ) { - return qfalse; - } - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n, *intPtr; - - if( vertexarray->size <= 0 || vertexarray->size > 4 ) { - return qfalse; - } - - // total number of values - n = header->num_vertexes * vertexarray->size; - - switch( vertexarray->format ) { - case IQM_BYTE: - case IQM_UBYTE: - // 1 byte, no swapping necessary - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(byte) ) ) { - return qfalse; - } - break; - case IQM_INT: - case IQM_UINT: - case IQM_FLOAT: - // 4-byte swap - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(float) ) ) { - return qfalse; - } - intPtr = (int *)((byte *)header + vertexarray->offset); - for( j = 0; j < n; j++, intPtr++ ) { - LL( *intPtr ); - } - break; - default: - // not supported - return qfalse; - break; - } - - switch( vertexarray->type ) { - case IQM_POSITION: - case IQM_NORMAL: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 3 ) { - return qfalse; - } - break; - case IQM_TANGENT: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 4 ) { - return qfalse; - } - break; - case IQM_TEXCOORD: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 2 ) { - return qfalse; - } - break; - case IQM_BLENDINDEXES: - if( (vertexarray->format != IQM_INT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendIndexesType = vertexarray->format; - break; - case IQM_BLENDWEIGHTS: - if( (vertexarray->format != IQM_FLOAT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendWeightsType = vertexarray->format; - break; - case IQM_COLOR: - if( vertexarray->format != IQM_UBYTE || - vertexarray->size != 4 ) { - return qfalse; - } - break; - } - } - - // check and swap triangles - if( IQM_CheckRange( header, header->ofs_triangles, - header->num_triangles, sizeof(iqmTriangle_t) ) ) { - return qfalse; - } - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - LL( triangle->vertex[0] ); - LL( triangle->vertex[1] ); - LL( triangle->vertex[2] ); - - if( triangle->vertex[0] > header->num_vertexes || - triangle->vertex[1] > header->num_vertexes || - triangle->vertex[2] > header->num_vertexes ) { - return qfalse; - } - } - - // check and swap meshes - if( IQM_CheckRange( header, header->ofs_meshes, - header->num_meshes, sizeof(iqmMesh_t) ) ) { - return qfalse; - } - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - for( i = 0; i < header->num_meshes; i++, mesh++) { - LL( mesh->name ); - LL( mesh->material ); - LL( mesh->first_vertex ); - LL( mesh->num_vertexes ); - LL( mesh->first_triangle ); - LL( mesh->num_triangles ); - - if ( mesh->name < header->num_text ) { - Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) ); - } else { - meshName[0] = '\0'; - } - - // check ioq3 limits - if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface", - mesh->num_vertexes ); - return qfalse; - } - if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface", - mesh->num_triangles ); - return qfalse; - } - - if( mesh->first_vertex >= header->num_vertexes || - mesh->first_vertex + mesh->num_vertexes > header->num_vertexes || - mesh->first_triangle >= header->num_triangles || - mesh->first_triangle + mesh->num_triangles > header->num_triangles || - mesh->name >= header->num_text || - mesh->material >= header->num_text ) { - return qfalse; - } - } - - if( header->num_poses != header->num_joints && header->num_poses != 0 ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n", - mod_name, header->num_poses, header->num_joints ); - return qfalse; - } - - joint_names = 0; - - if ( header->num_joints ) - { - // check and swap joints - if( IQM_CheckRange( header, header->ofs_joints, - header->num_joints, sizeof(iqmJoint_t) ) ) { - return qfalse; - } - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - LL( joint->name ); - LL( joint->parent ); - LL( joint->translate[0] ); - LL( joint->translate[1] ); - LL( joint->translate[2] ); - LL( joint->rotate[0] ); - LL( joint->rotate[1] ); - LL( joint->rotate[2] ); - LL( joint->rotate[3] ); - LL( joint->scale[0] ); - LL( joint->scale[1] ); - LL( joint->scale[2] ); - - if( joint->parent < -1 || - joint->parent >= (int)header->num_joints || - joint->name >= (int)header->num_text ) { - return qfalse; - } - joint_names += strlen( (char *)header + header->ofs_text + - joint->name ) + 1; - } - } - - if ( header->num_poses ) - { - // check and swap poses - if( IQM_CheckRange( header, header->ofs_poses, - header->num_poses, sizeof(iqmPose_t) ) ) { - return qfalse; - } - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( i = 0; i < header->num_poses; i++, pose++ ) { - LL( pose->parent ); - LL( pose->mask ); - LL( pose->channeloffset[0] ); - LL( pose->channeloffset[1] ); - LL( pose->channeloffset[2] ); - LL( pose->channeloffset[3] ); - LL( pose->channeloffset[4] ); - LL( pose->channeloffset[5] ); - LL( pose->channeloffset[6] ); - LL( pose->channeloffset[7] ); - LL( pose->channeloffset[8] ); - LL( pose->channeloffset[9] ); - LL( pose->channelscale[0] ); - LL( pose->channelscale[1] ); - LL( pose->channelscale[2] ); - LL( pose->channelscale[3] ); - LL( pose->channelscale[4] ); - LL( pose->channelscale[5] ); - LL( pose->channelscale[6] ); - LL( pose->channelscale[7] ); - LL( pose->channelscale[8] ); - LL( pose->channelscale[9] ); - } - } - - if (header->ofs_bounds) - { - // check and swap model bounds - if(IQM_CheckRange(header, header->ofs_bounds, - header->num_frames, sizeof(*bounds))) - { - return qfalse; - } - bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds); - for(i = 0; i < header->num_frames; i++) - { - LL(bounds->bbmin[0]); - LL(bounds->bbmin[1]); - LL(bounds->bbmin[2]); - LL(bounds->bbmax[0]); - LL(bounds->bbmax[1]); - LL(bounds->bbmax[2]); - - bounds++; - } - } - - // allocate the model and copy the data - size = sizeof(iqmData_t); - size += header->num_meshes * sizeof( srfIQModel_t ); - size += header->num_joints * 12 * sizeof( float ); // joint mats - size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats - if(header->ofs_bounds) - size += header->num_frames * 6 * sizeof(float); // model bounds - size += header->num_vertexes * 3 * sizeof(float); // positions - size += header->num_vertexes * 2 * sizeof(float); // texcoords - size += header->num_vertexes * 3 * sizeof(float); // normals - size += header->num_vertexes * 4 * sizeof(float); // tangents - size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes - size += header->num_vertexes * 4 * sizeof(byte); // colors - size += header->num_joints * sizeof(int); // parents - size += header->num_triangles * 3 * sizeof(int); // triangles - size += joint_names; // joint names - - // blendWeights - if (blendWeightsType == IQM_FLOAT) { - size += header->num_vertexes * 4 * sizeof(float); - } else { - size += header->num_vertexes * 4 * sizeof(byte); - } - - mod->type = MOD_IQM; - iqmData = (iqmData_t *)ri.Hunk_Alloc( size, h_low ); - mod->modelData = iqmData; - - // fill header - iqmData->num_vertexes = header->num_vertexes; - iqmData->num_triangles = header->num_triangles; - iqmData->num_frames = header->num_frames; - iqmData->num_surfaces = header->num_meshes; - iqmData->num_joints = header->num_joints; - iqmData->num_poses = header->num_poses; - iqmData->blendWeightsType = blendWeightsType; - iqmData->surfaces = (srfIQModel_t *)(iqmData + 1); - iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); - iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints; - if(header->ofs_bounds) - { - iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->positions = iqmData->bounds + 6 * header->num_frames; - } - else - iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes; - iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes; - iqmData->tangents = iqmData->normals + 3 * header->num_vertexes; - iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes); - - if(blendWeightsType == IQM_FLOAT) { - iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes); - iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes); - } else { - iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes; - iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes; - } - - iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes); - iqmData->triangles = iqmData->jointParents + header->num_joints; - iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles); - - if ( header->num_joints == 0 ) - iqmData->jointMats = NULL; - - if ( header->num_poses == 0 ) - iqmData->poseMats = NULL; - - // calculate joint matrices and their inverses - // joint inverses are needed only until the pose matrices are calculated - mat = iqmData->jointMats; - matInv = jointInvMats; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - float baseFrame[12], invBaseFrame[12]; - - JointToMatrix( joint->rotate, joint->scale, joint->translate, baseFrame ); - Matrix34Invert( baseFrame, invBaseFrame ); - - if ( joint->parent >= 0 ) - { - Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat ); - mat += 12; - Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv ); - matInv += 12; - } - else - { - Com_Memcpy( mat, baseFrame, sizeof(baseFrame) ); - mat += 12; - Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) ); - matInv += 12; - } - } - - // calculate pose matrices - framedata = (unsigned short *)((byte *)header + header->ofs_frames); - mat = iqmData->poseMats; - for( i = 0; i < header->num_frames; i++ ) { - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( j = 0; j < header->num_poses; j++, pose++ ) { - vec3_t translate; - vec4_t rotate; - vec3_t scale; - float mat1[12], mat2[12]; - - translate[0] = pose->channeloffset[0]; - if( pose->mask & 0x001) - translate[0] += *framedata++ * pose->channelscale[0]; - translate[1] = pose->channeloffset[1]; - if( pose->mask & 0x002) - translate[1] += *framedata++ * pose->channelscale[1]; - translate[2] = pose->channeloffset[2]; - if( pose->mask & 0x004) - translate[2] += *framedata++ * pose->channelscale[2]; - - rotate[0] = pose->channeloffset[3]; - if( pose->mask & 0x008) - rotate[0] += *framedata++ * pose->channelscale[3]; - rotate[1] = pose->channeloffset[4]; - if( pose->mask & 0x010) - rotate[1] += *framedata++ * pose->channelscale[4]; - rotate[2] = pose->channeloffset[5]; - if( pose->mask & 0x020) - rotate[2] += *framedata++ * pose->channelscale[5]; - rotate[3] = pose->channeloffset[6]; - if( pose->mask & 0x040) - rotate[3] += *framedata++ * pose->channelscale[6]; - - scale[0] = pose->channeloffset[7]; - if( pose->mask & 0x080) - scale[0] += *framedata++ * pose->channelscale[7]; - scale[1] = pose->channeloffset[8]; - if( pose->mask & 0x100) - scale[1] += *framedata++ * pose->channelscale[8]; - scale[2] = pose->channeloffset[9]; - if( pose->mask & 0x200) - scale[2] += *framedata++ * pose->channelscale[9]; - - // construct transformation matrix - JointToMatrix( rotate, scale, translate, mat1 ); - - if( pose->parent >= 0 ) { - Matrix34Multiply( iqmData->jointMats + 12 * pose->parent, - mat1, mat2 ); - } else { - Com_Memcpy( mat2, mat1, sizeof(mat1) ); - } - - Matrix34Multiply( mat2, jointInvMats + 12 * j, mat ); - mat += 12; - } - } - - // register shaders - // overwrite the material offset with the shader index - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - surface = iqmData->surfaces; - str = (char *)header + header->ofs_text; - for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) { - surface->surfaceType = SF_IQM; - Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name)); - Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster - surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue ); - if( surface->shader->defaultShader ) - surface->shader = tr.defaultShader; - surface->data = iqmData; - surface->first_vertex = mesh->first_vertex; - surface->num_vertexes = mesh->num_vertexes; - surface->first_triangle = mesh->first_triangle; - surface->num_triangles = mesh->num_triangles; - } - - // copy vertexarrays and indexes - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n; - - // total number of values - n = header->num_vertexes * vertexarray->size; - - switch( vertexarray->type ) { - case IQM_POSITION: - Com_Memcpy( iqmData->positions, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_NORMAL: - Com_Memcpy( iqmData->normals, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TANGENT: - Com_Memcpy( iqmData->tangents, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TEXCOORD: - Com_Memcpy( iqmData->texcoords, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_BLENDINDEXES: - if( blendIndexesType == IQM_INT ) { - int *data = (int*)((byte*)header + vertexarray->offset); - for ( j = 0; j < n; j++ ) { - iqmData->blendIndexes[j] = (byte)data[j]; - } - } else { - Com_Memcpy( iqmData->blendIndexes, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - } - break; - case IQM_BLENDWEIGHTS: - if( blendWeightsType == IQM_FLOAT ) { - Com_Memcpy( iqmData->blendWeights.f, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - } else { - Com_Memcpy( iqmData->blendWeights.b, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - } - break; - case IQM_COLOR: - Com_Memcpy( iqmData->colors, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - break; - } - } - - // copy joint parents - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - iqmData->jointParents[i] = joint->parent; - } - - // copy triangles - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - iqmData->triangles[3*i+0] = triangle->vertex[0]; - iqmData->triangles[3*i+1] = triangle->vertex[1]; - iqmData->triangles[3*i+2] = triangle->vertex[2]; - } - - // copy joint names - str = iqmData->names; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - char *name = (char *)header + header->ofs_text + - joint->name; - int len = strlen( name ) + 1; - Com_Memcpy( str, name, len ); - str += len; - } - - // copy model bounds - if(header->ofs_bounds) - { - mat = iqmData->bounds; - bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds); - for(i = 0; i < header->num_frames; i++) - { - mat[0] = bounds->bbmin[0]; - mat[1] = bounds->bbmin[1]; - mat[2] = bounds->bbmin[2]; - mat[3] = bounds->bbmax[0]; - mat[4] = bounds->bbmax[1]; - mat[5] = bounds->bbmax[2]; - - mat += 6; - bounds++; - } - } - - return qtrue; -} - -/* -============= -R_CullIQM -============= -*/ -static int R_CullIQM( iqmData_t *data, trRefEntity_t *ent ) { - vec3_t bounds[2]; - vec_t *oldBounds, *newBounds; - int i; - - if (!data->bounds) { - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - } - - // compute bounds pointers - oldBounds = data->bounds + 6*ent->e.oldframe; - newBounds = data->bounds + 6*ent->e.frame; - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldBounds[i] < newBounds[i] ? oldBounds[i] : newBounds[i]; - bounds[1][i] = oldBounds[i+3] > newBounds[i+3] ? oldBounds[i+3] : newBounds[i+3]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - -/* -================= -R_ComputeIQMFogNum - -================= -*/ -int R_ComputeIQMFogNum( iqmData_t *data, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - const vec_t *bounds; - const vec_t defaultBounds[6] = { -8, -8, -8, 8, 8, 8 }; - vec3_t diag, center; - vec3_t localOrigin; - vec_t radius; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - // FIXME: non-normalized axis issues - if (data->bounds) { - bounds = data->bounds + 6*ent->e.frame; - } else { - bounds = defaultBounds; - } - VectorSubtract( bounds+3, bounds, diag ); - VectorMA( bounds, 0.5f, diag, center ); - VectorAdd( ent->e.origin, center, localOrigin ); - radius = 0.5f * VectorLength( diag ); - - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -================= -R_AddIQMSurfaces - -Add all surfaces of this model -================= -*/ -void R_AddIQMSurfaces( trRefEntity_t *ent ) { - iqmData_t *data; - srfIQModel_t *surface; - int i, j; - qboolean personalModel; - int cull; - int fogNum; - shader_t *shader; - skin_t *skin; - - data = tr.currentModel->modelData; - surface = data->surfaces; - - // don't add third_person objects if not in a portal - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) { - ent->e.frame %= data->num_frames; - ent->e.oldframe %= data->num_frames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ( (ent->e.frame >= data->num_frames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= data->num_frames) - || (ent->e.oldframe < 0) ) { - ri.Printf( PRINT_DEVELOPER, "R_AddIQMSurfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, - tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_CullIQM ( data, ent ); - if ( cull == CULL_OUT ) { - return; - } - - // - // set up lighting now that we know we aren't culled - // - if ( !personalModel || r_shadows->integer > 1 ) { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // - // see if we are in a fog volume - // - fogNum = R_ComputeIQMFogNum( data, ent ); - - for ( i = 0 ; i < data->num_surfaces ; i++ ) { - if(ent->e.customShader) - shader = R_GetShaderByHandle( ent->e.customShader ); - else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) - { - skin = R_GetSkinByHandle(ent->e.customSkin); - shader = tr.defaultShader; - - for(j = 0; j < skin->numSurfaces; j++) - { - if (!strcmp(skin->surfaces[j]->name, surface->name)) - { - shader = skin->surfaces[j]->shader; - break; - } - } - } else { - shader = surface->shader; - } - - // we will add shadows even if the main object isn't visible in the view - - // stencil shadows can't do personal models unless I polyhedron clip - if ( !personalModel - && r_shadows->integer == 2 - && fogNum == 0 - && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, 0 ); - } - - // projection shadows work fine with personal models - if ( r_shadows->integer == 3 - && fogNum == 0 - && (ent->e.renderfx & RF_SHADOW_PLANE ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0 ); - } - - if( !personalModel ) { - R_AddDrawSurf( (void *)surface, shader, fogNum, 0 ); - } - - surface++; - } -} - - -static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, - float backlerp, float *mat ) { - float *mat1, *mat2; - int *joint = data->jointParents; - int i; - - if ( data->num_poses == 0 ) { - for( i = 0; i < data->num_joints; i++, joint++ ) { - if( *joint >= 0 ) { - Matrix34Multiply( mat + 12 * *joint, - identityMatrix, mat + 12*i ); - } else { - Com_Memcpy( mat + 12*i, identityMatrix, 12 * sizeof(float) ); - } - } - return; - } - - if ( oldframe == frame ) { - mat1 = data->poseMats + 12 * data->num_poses * frame; - for( i = 0; i < data->num_poses; i++, joint++ ) { - if( *joint >= 0 ) { - Matrix34Multiply( mat + 12 * *joint, - mat1 + 12*i, mat + 12*i ); - } else { - Com_Memcpy( mat + 12*i, mat1 + 12*i, 12 * sizeof(float) ); - } - } - } else { - mat1 = data->poseMats + 12 * data->num_poses * frame; - mat2 = data->poseMats + 12 * data->num_poses * oldframe; - - for( i = 0; i < data->num_poses; i++, joint++ ) { - if( *joint >= 0 ) { - float tmpMat[12]; - InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, - backlerp, tmpMat ); - Matrix34Multiply( mat + 12 * *joint, - tmpMat, mat + 12*i ); - - } else { - InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, - backlerp, mat ); - } - } - } -} - -static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, - float backlerp, float *mat ) { - float *mat1; - int i; - - ComputePoseMats( data, frame, oldframe, backlerp, mat ); - - for( i = 0; i < data->num_joints; i++ ) { - float outmat[12]; - mat1 = mat + 12 * i; - - Com_Memcpy(outmat, mat1, sizeof(outmat)); - - Matrix34Multiply_OnlySetOrigin( outmat, data->jointMats + 12 * i, mat1 ); - } -} - - -/* -================= -RB_AddIQMSurfaces - -Compute vertices for this model surface -================= -*/ -void RB_IQMSurfaceAnim( surfaceType_t *surface ) { - srfIQModel_t *surf = (srfIQModel_t *)surface; - iqmData_t *data = surf->data; - float jointMats[IQM_MAX_JOINTS * 12]; - int i; - - vec4_t *outXYZ; - vec4_t *outNormal; - vec2_t (*outTexCoord)[2]; - color4ub_t *outColor; - - int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0; - int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0; - float backlerp = backEnd.currentEntity->e.backlerp; - - int *tri; - glIndex_t *ptr; - glIndex_t base; - - RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 ); - - outXYZ = &tess.xyz[tess.numVertexes]; - outNormal = &tess.normal[tess.numVertexes]; - outTexCoord = &tess.texCoords[tess.numVertexes]; - outColor = &tess.vertexColors[tess.numVertexes]; - - // compute interpolated joint matrices - if ( data->num_poses > 0 ) { - ComputePoseMats( data, frame, oldframe, backlerp, jointMats ); - } - - // transform vertexes and fill other data - for( i = 0; i < surf->num_vertexes; - i++, outXYZ++, outNormal++, outTexCoord++, outColor++ ) { - int j, k; - float vtxMat[12]; - float nrmMat[9]; - int vtx = i + surf->first_vertex; - float blendWeights[4]; - int numWeights; - - for ( numWeights = 0; numWeights < 4; numWeights++ ) { - if ( data->blendWeightsType == IQM_FLOAT ) - blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights]; - else - blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f; - - if ( blendWeights[numWeights] <= 0 ) - break; - } - - if ( data->num_poses == 0 || numWeights == 0 ) { - // no blend joint, use identity matrix. - Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) ); - } else { - // compute the vertex matrix by blending the up to - // four blend weights - Com_Memset( vtxMat, 0, 12 * sizeof (float) ); - for( j = 0; j < numWeights; j++ ) { - for( k = 0; k < 12; k++ ) { - vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k]; - } - } - } - - // compute the normal matrix as transpose of the adjoint - // of the vertex matrix - nrmMat[ 0] = vtxMat[ 5]*vtxMat[10] - vtxMat[ 6]*vtxMat[ 9]; - nrmMat[ 1] = vtxMat[ 6]*vtxMat[ 8] - vtxMat[ 4]*vtxMat[10]; - nrmMat[ 2] = vtxMat[ 4]*vtxMat[ 9] - vtxMat[ 5]*vtxMat[ 8]; - nrmMat[ 3] = vtxMat[ 2]*vtxMat[ 9] - vtxMat[ 1]*vtxMat[10]; - nrmMat[ 4] = vtxMat[ 0]*vtxMat[10] - vtxMat[ 2]*vtxMat[ 8]; - nrmMat[ 5] = vtxMat[ 1]*vtxMat[ 8] - vtxMat[ 0]*vtxMat[ 9]; - nrmMat[ 6] = vtxMat[ 1]*vtxMat[ 6] - vtxMat[ 2]*vtxMat[ 5]; - nrmMat[ 7] = vtxMat[ 2]*vtxMat[ 4] - vtxMat[ 0]*vtxMat[ 6]; - nrmMat[ 8] = vtxMat[ 0]*vtxMat[ 5] - vtxMat[ 1]*vtxMat[ 4]; - - (*outTexCoord)[0][0] = data->texcoords[2*vtx + 0]; - (*outTexCoord)[0][1] = data->texcoords[2*vtx + 1]; - (*outTexCoord)[1][0] = (*outTexCoord)[0][0]; - (*outTexCoord)[1][1] = (*outTexCoord)[0][1]; - - (*outXYZ)[0] = - vtxMat[ 0] * data->positions[3*vtx+0] + - vtxMat[ 1] * data->positions[3*vtx+1] + - vtxMat[ 2] * data->positions[3*vtx+2] + - vtxMat[ 3]; - (*outXYZ)[1] = - vtxMat[ 4] * data->positions[3*vtx+0] + - vtxMat[ 5] * data->positions[3*vtx+1] + - vtxMat[ 6] * data->positions[3*vtx+2] + - vtxMat[ 7]; - (*outXYZ)[2] = - vtxMat[ 8] * data->positions[3*vtx+0] + - vtxMat[ 9] * data->positions[3*vtx+1] + - vtxMat[10] * data->positions[3*vtx+2] + - vtxMat[11]; - (*outXYZ)[3] = 1.0f; - - (*outNormal)[0] = - nrmMat[ 0] * data->normals[3*vtx+0] + - nrmMat[ 1] * data->normals[3*vtx+1] + - nrmMat[ 2] * data->normals[3*vtx+2]; - (*outNormal)[1] = - nrmMat[ 3] * data->normals[3*vtx+0] + - nrmMat[ 4] * data->normals[3*vtx+1] + - nrmMat[ 5] * data->normals[3*vtx+2]; - (*outNormal)[2] = - nrmMat[ 6] * data->normals[3*vtx+0] + - nrmMat[ 7] * data->normals[3*vtx+1] + - nrmMat[ 8] * data->normals[3*vtx+2]; - (*outNormal)[3] = 0.0f; - - (*outColor)[0] = data->colors[4*vtx+0]; - (*outColor)[1] = data->colors[4*vtx+1]; - (*outColor)[2] = data->colors[4*vtx+2]; - (*outColor)[3] = data->colors[4*vtx+3]; - } - - tri = data->triangles + 3 * surf->first_triangle; - ptr = &tess.indexes[tess.numIndexes]; - base = tess.numVertexes; - - for( i = 0; i < surf->num_triangles; i++ ) { - *ptr++ = base + (*tri++ - surf->first_vertex); - *ptr++ = base + (*tri++ - surf->first_vertex); - *ptr++ = base + (*tri++ - surf->first_vertex); - } - - tess.numIndexes += 3 * surf->num_triangles; - tess.numVertexes += surf->num_vertexes; -} - -int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, - int startFrame, int endFrame, - float frac, const char *tagName ) { - float jointMats[IQM_MAX_JOINTS * 12]; - int joint; - char *names = data->names; - - // get joint number by reading the joint names - for( joint = 0; joint < data->num_joints; joint++ ) { - if( !strcmp( tagName, names ) ) - break; - names += strlen( names ) + 1; - } - if( joint >= data->num_joints ) { - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - } - - ComputeJointMats( data, startFrame, endFrame, frac, jointMats ); - - tag->axis[0][0] = jointMats[12 * joint + 0]; - tag->axis[1][0] = jointMats[12 * joint + 1]; - tag->axis[2][0] = jointMats[12 * joint + 2]; - tag->origin[0] = jointMats[12 * joint + 3]; - tag->axis[0][1] = jointMats[12 * joint + 4]; - tag->axis[1][1] = jointMats[12 * joint + 5]; - tag->axis[2][1] = jointMats[12 * joint + 6]; - tag->origin[1] = jointMats[12 * joint + 7]; - tag->axis[0][2] = jointMats[12 * joint + 8]; - tag->axis[1][2] = jointMats[12 * joint + 9]; - tag->axis[2][2] = jointMats[12 * joint + 10]; - tag->origin[2] = jointMats[12 * joint + 11]; - - return qtrue; -} diff --git a/code/renderergl1/tr_scene.c b/code/renderergl1/tr_scene.c deleted file mode 100644 index 5d7a3dd1a5..0000000000 --- a/code/renderergl1/tr_scene.c +++ /dev/null @@ -1,411 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -int r_firstSceneDrawSurf; - -int r_numdlights; -int r_firstSceneDlight; - -int r_numentities; -int r_firstSceneEntity; - -int r_numpolys; -int r_firstScenePoly; - -int r_numpolyverts; - - -/* -==================== -R_InitNextFrame - -==================== -*/ -void R_InitNextFrame( void ) { - backEndData->commands.used = 0; - - r_firstSceneDrawSurf = 0; - - r_numdlights = 0; - r_firstSceneDlight = 0; - - r_numentities = 0; - r_firstSceneEntity = 0; - - r_numpolys = 0; - r_firstScenePoly = 0; - - r_numpolyverts = 0; -} - - -/* -==================== -RE_ClearScene - -==================== -*/ -void RE_ClearScene( void ) { - r_firstSceneDlight = r_numdlights; - r_firstSceneEntity = r_numentities; - r_firstScenePoly = r_numpolys; -} - -/* -=========================================================================== - -DISCRETE POLYS - -=========================================================================== -*/ - -/* -===================== -R_AddPolygonSurfaces - -Adds all the scene's polys into this view's drawsurf list -===================== -*/ -void R_AddPolygonSurfaces( void ) { - int i; - shader_t *sh; - srfPoly_t *poly; - - tr.currentEntityNum = REFENTITYNUM_WORLD; - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - - for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) { - sh = R_GetShaderByHandle( poly->hShader ); - R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse ); - } -} - -/* -===================== -RE_AddPolyToScene - -===================== -*/ -void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) { - srfPoly_t *poly; - int i, j; - int fogIndex; - fog_t *fog; - vec3_t bounds[2]; - - if ( !tr.registered ) { - return; - } - - if ( !hShader ) { - ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n"); - return; - } - - for ( j = 0; j < numPolys; j++ ) { - if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) { - /* - NOTE TTimo this was initially a PRINT_WARNING - but it happens a lot with high fighting scenes and particles - since we don't plan on changing the const and making for room for those effects - simply cut this message to developer only - */ - ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n"); - return; - } - - poly = &backEndData->polys[r_numpolys]; - poly->surfaceType = SF_POLY; - poly->hShader = hShader; - poly->numVerts = numVerts; - poly->verts = &backEndData->polyVerts[r_numpolyverts]; - - Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) ); - - if ( glConfig.hardwareType == GLHW_RAGEPRO ) { - poly->verts->modulate[0] = 255; - poly->verts->modulate[1] = 255; - poly->verts->modulate[2] = 255; - poly->verts->modulate[3] = 255; - } - // done. - r_numpolys++; - r_numpolyverts += numVerts; - - // if no world is loaded - if ( tr.world == NULL ) { - fogIndex = 0; - } - // see if it is in a fog volume - else if ( tr.world->numfogs == 1 ) { - fogIndex = 0; - } else { - // find which fog volume the poly is in - VectorCopy( poly->verts[0].xyz, bounds[0] ); - VectorCopy( poly->verts[0].xyz, bounds[1] ); - for ( i = 1 ; i < poly->numVerts ; i++ ) { - AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] ); - } - for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) { - fog = &tr.world->fogs[fogIndex]; - if ( bounds[1][0] >= fog->bounds[0][0] - && bounds[1][1] >= fog->bounds[0][1] - && bounds[1][2] >= fog->bounds[0][2] - && bounds[0][0] <= fog->bounds[1][0] - && bounds[0][1] <= fog->bounds[1][1] - && bounds[0][2] <= fog->bounds[1][2] ) { - break; - } - } - if ( fogIndex == tr.world->numfogs ) { - fogIndex = 0; - } - } - poly->fogIndex = fogIndex; - } -} - - -//================================================================================= - - -/* -===================== -RE_AddRefEntityToScene - -===================== -*/ -void RE_AddRefEntityToScene( const refEntity_t *ent ) { - if ( !tr.registered ) { - return; - } - if ( r_numentities >= MAX_REFENTITIES ) { - ri.Printf(PRINT_DEVELOPER, "RE_AddRefEntityToScene: Dropping refEntity, reached MAX_REFENTITIES\n"); - return; - } - if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) { - static qboolean firstTime = qtrue; - if (firstTime) { - firstTime = qfalse; - ri.Printf( PRINT_WARNING, "RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n"); - } - return; - } - if ( (int)ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) { - ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType ); - } - - backEndData->entities[r_numentities].e = *ent; - backEndData->entities[r_numentities].lightingCalculated = qfalse; - - r_numentities++; -} - - -/* -===================== -RE_AddDynamicLightToScene - -===================== -*/ -void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) { - dlight_t *dl; - - if ( !tr.registered ) { - return; - } - if ( r_numdlights >= MAX_DLIGHTS ) { - return; - } - if ( intensity <= 0 ) { - return; - } - // these cards don't have the correct blend mode - if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - return; - } - dl = &backEndData->dlights[r_numdlights++]; - VectorCopy (org, dl->origin); - dl->radius = intensity; - dl->color[0] = r; - dl->color[1] = g; - dl->color[2] = b; - dl->additive = additive; -} - -/* -===================== -RE_AddLightToScene - -===================== -*/ -void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { - RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse ); -} - -/* -===================== -RE_AddAdditiveLightToScene - -===================== -*/ -void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { - RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue ); -} - -/* -@@@@@@@@@@@@@@@@@@@@@ -RE_RenderScene - -Draw a 3D view into a part of the window, then return -to 2D drawing. - -Rendering a scene may require multiple views to be rendered -to handle mirrors, -@@@@@@@@@@@@@@@@@@@@@ -*/ -void RE_RenderScene( const refdef_t *fd ) { - viewParms_t parms; - int startTime; - - if ( !tr.registered ) { - return; - } - GLimp_LogComment( "====== RE_RenderScene =====\n" ); - - if ( r_norefresh->integer ) { - return; - } - - startTime = ri.Milliseconds(); - - if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { - ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); - } - - Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) ); - - tr.refdef.x = fd->x; - tr.refdef.y = fd->y; - tr.refdef.width = fd->width; - tr.refdef.height = fd->height; - tr.refdef.fov_x = fd->fov_x; - tr.refdef.fov_y = fd->fov_y; - - VectorCopy( fd->vieworg, tr.refdef.vieworg ); - VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] ); - VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] ); - VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] ); - - tr.refdef.time = fd->time; - tr.refdef.rdflags = fd->rdflags; - - // copy the areamask data over and note if it has changed, which - // will force a reset of the visible leafs even if the view hasn't moved - tr.refdef.areamaskModified = qfalse; - if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) { - int areaDiff; - int i; - - // compare the area bits - areaDiff = 0; - for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) { - areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i]; - ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i]; - } - - if ( areaDiff ) { - // a door just opened or something - tr.refdef.areamaskModified = qtrue; - } - } - - - // derived info - - tr.refdef.floatTime = tr.refdef.time * 0.001f; - - tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; - tr.refdef.drawSurfs = backEndData->drawSurfs; - - tr.refdef.num_entities = r_numentities - r_firstSceneEntity; - tr.refdef.entities = &backEndData->entities[r_firstSceneEntity]; - - tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; - tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight]; - - tr.refdef.numPolys = r_numpolys - r_firstScenePoly; - tr.refdef.polys = &backEndData->polys[r_firstScenePoly]; - - // turn off dynamic lighting globally by clearing all the - // dlights if it needs to be disabled or if vertex lighting is enabled - if ( r_dynamiclight->integer == 0 || - r_vertexLight->integer == 1 || - glConfig.hardwareType == GLHW_PERMEDIA2 ) { - tr.refdef.num_dlights = 0; - } - - // a single frame may have multiple scenes draw inside it -- - // a 3D game view, 3D status bar renderings, 3D menus, etc. - // They need to be distinguished by the light flare code, because - // the visibility state for a given surface may be different in - // each scene / view. - tr.frameSceneNum++; - tr.sceneCount++; - - // setup view parms for the initial view - // - // set up viewport - // The refdef takes 0-at-the-top y coordinates, so - // convert to GL's 0-at-the-bottom space - // - Com_Memset( &parms, 0, sizeof( parms ) ); - parms.viewportX = tr.refdef.x; - parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); - parms.viewportWidth = tr.refdef.width; - parms.viewportHeight = tr.refdef.height; - parms.isPortal = qfalse; - - parms.fovX = tr.refdef.fov_x; - parms.fovY = tr.refdef.fov_y; - - parms.stereoFrame = tr.refdef.stereoFrame; - - VectorCopy( fd->vieworg, parms.or.origin ); - VectorCopy( fd->viewaxis[0], parms.or.axis[0] ); - VectorCopy( fd->viewaxis[1], parms.or.axis[1] ); - VectorCopy( fd->viewaxis[2], parms.or.axis[2] ); - - VectorCopy( fd->vieworg, parms.pvsOrigin ); - - R_RenderView( &parms ); - - // the next scene rendered in this frame will tack on after this one - r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; - r_firstSceneEntity = r_numentities; - r_firstSceneDlight = r_numdlights; - r_firstScenePoly = r_numpolys; - - tr.frontEndMsec += ri.Milliseconds() - startTime; -} diff --git a/code/renderergl1/tr_shade.c b/code/renderergl1/tr_shade.c deleted file mode 100644 index 08648b2e8a..0000000000 --- a/code/renderergl1/tr_shade.c +++ /dev/null @@ -1,1522 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_shade.c - -#include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - -/* - - THIS ENTIRE FILE IS BACK END - - This file deals with applying shaders to surface data in the tess struct. -*/ - -/* -================ -R_ArrayElementDiscrete - -This is just for OpenGL conformance testing, it should never be the fastest -================ -*/ -static void APIENTRY R_ArrayElementDiscrete( GLint index ) { - qglColor4ubv( tess.svars.colors[ index ] ); - if ( glState.currenttmu ) { - qglMultiTexCoord2fARB( 0, tess.svars.texcoords[ 0 ][ index ][0], tess.svars.texcoords[ 0 ][ index ][1] ); - qglMultiTexCoord2fARB( 1, tess.svars.texcoords[ 1 ][ index ][0], tess.svars.texcoords[ 1 ][ index ][1] ); - } else { - qglTexCoord2fv( tess.svars.texcoords[ 0 ][ index ] ); - } - qglVertex3fv( tess.xyz[ index ] ); -} - -/* -=================== -R_DrawStripElements - -=================== -*/ -static int c_vertexes; // for seeing how long our average strips are -static int c_begins; -static void R_DrawStripElements( int numIndexes, const glIndex_t *indexes, void ( APIENTRY *element )(GLint) ) { - int i; - int last[3] = { -1, -1, -1 }; - qboolean even; - - c_begins++; - - if ( numIndexes <= 0 ) { - return; - } - - qglBegin( GL_TRIANGLE_STRIP ); - - // prime the strip - element( indexes[0] ); - element( indexes[1] ); - element( indexes[2] ); - c_vertexes += 3; - - last[0] = indexes[0]; - last[1] = indexes[1]; - last[2] = indexes[2]; - - even = qfalse; - - for ( i = 3; i < numIndexes; i += 3 ) - { - // odd numbered triangle in potential strip - if ( !even ) - { - // check previous triangle to see if we're continuing a strip - if ( ( indexes[i+0] == last[2] ) && ( indexes[i+1] == last[1] ) ) - { - element( indexes[i+2] ); - c_vertexes++; - assert( indexes[i+2] < tess.numVertexes ); - even = qtrue; - } - // otherwise we're done with this strip so finish it and start - // a new one - else - { - qglEnd(); - - qglBegin( GL_TRIANGLE_STRIP ); - c_begins++; - - element( indexes[i+0] ); - element( indexes[i+1] ); - element( indexes[i+2] ); - - c_vertexes += 3; - - even = qfalse; - } - } - else - { - // check previous triangle to see if we're continuing a strip - if ( ( last[2] == indexes[i+1] ) && ( last[0] == indexes[i+0] ) ) - { - element( indexes[i+2] ); - c_vertexes++; - - even = qfalse; - } - // otherwise we're done with this strip so finish it and start - // a new one - else - { - qglEnd(); - - qglBegin( GL_TRIANGLE_STRIP ); - c_begins++; - - element( indexes[i+0] ); - element( indexes[i+1] ); - element( indexes[i+2] ); - c_vertexes += 3; - - even = qfalse; - } - } - - // cache the last three vertices - last[0] = indexes[i+0]; - last[1] = indexes[i+1]; - last[2] = indexes[i+2]; - } - - qglEnd(); -} - - - -/* -================== -R_DrawElements - -Optionally performs our own glDrawElements that looks for strip conditions -instead of using the single glDrawElements call that may be inefficient -without compiled vertex arrays. -================== -*/ -static void R_DrawElements( int numIndexes, const glIndex_t *indexes ) { - int primitives; - - primitives = r_primitives->integer; - - // default is to use triangles if compiled vertex arrays are present - if ( primitives == 0 ) { - if ( qglLockArraysEXT ) { - primitives = 2; - } else { - primitives = 1; - } - } - - - if ( primitives == 2 ) { - qglDrawElements( GL_TRIANGLES, - numIndexes, - GL_INDEX_TYPE, - indexes ); - return; - } - - if ( primitives == 1 ) { - R_DrawStripElements( numIndexes, indexes, qglArrayElement ); - return; - } - - if ( primitives == 3 ) { - R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete ); - return; - } - - // anything else will cause no drawing -} - - -/* -============================================================= - -SURFACE SHADERS - -============================================================= -*/ - -shaderCommands_t tess; -static qboolean setArraysOnce; - -/* -================= -R_BindAnimatedImage - -================= -*/ -static void R_BindAnimatedImage( textureBundle_t *bundle ) { - int index; - - if ( bundle->isVideoMap ) { - ri.CIN_RunCinematic(bundle->videoMapHandle); - ri.CIN_UploadCinematic(bundle->videoMapHandle); - return; - } - - if ( bundle->numImageAnimations <= 1 ) { - GL_Bind( bundle->image[0] ); - return; - } - - // it is necessary to do this messy calc to make sure animations line up - // exactly with waveforms of the same frequency - index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); - index >>= FUNCTABLE_SIZE2; - - if ( index < 0 ) { - index = 0; // may happen with shader time offsets - } - index %= bundle->numImageAnimations; - - GL_Bind( bundle->image[ index ] ); -} - -/* -================ -DrawTris - -Draws triangle outlines for debugging -================ -*/ -static void DrawTris (shaderCommands_t *input) { - GL_Bind( tr.whiteImage ); - qglColor3f (1,1,1); - - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); - qglDepthRange( 0, 0 ); - - qglDisableClientState (GL_COLOR_ARRAY); - qglDisableClientState (GL_TEXTURE_COORD_ARRAY); - - qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD - - if (qglLockArraysEXT) { - qglLockArraysEXT(0, input->numVertexes); - GLimp_LogComment( "glLockArraysEXT\n" ); - } - - R_DrawElements( input->numIndexes, input->indexes ); - - if (qglUnlockArraysEXT) { - qglUnlockArraysEXT(); - GLimp_LogComment( "glUnlockArraysEXT\n" ); - } - qglDepthRange( 0, 1 ); -} - - -/* -================ -DrawNormals - -Draws vertex normals for debugging -================ -*/ -static void DrawNormals (shaderCommands_t *input) { - int i; - vec3_t temp; - - GL_Bind( tr.whiteImage ); - qglColor3f (1,1,1); - qglDepthRange( 0, 0 ); // never occluded - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); - - qglBegin (GL_LINES); - for (i = 0 ; i < input->numVertexes ; i++) { - qglVertex3fv (input->xyz[i]); - VectorMA (input->xyz[i], 2, input->normal[i], temp); - qglVertex3fv (temp); - } - qglEnd (); - - qglDepthRange( 0, 1 ); -} - -/* -============== -RB_BeginSurface - -We must set some things up before beginning any tesselation, -because a surface may be forced to perform a RB_End due -to overflow. -============== -*/ -void RB_BeginSurface( shader_t *shader, int fogNum ) { - - shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader; - - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.shader = state; - tess.fogNum = fogNum; - tess.dlightBits = 0; // will be OR'd in by surface functions - tess.xstages = state->stages; - tess.numPasses = state->numUnfoggedPasses; - tess.currentStageIteratorFunc = state->optimalStageIteratorFunc; - - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) { - tess.shaderTime = tess.shader->clampTime; - } - - -} - -/* -=================== -DrawMultitextured - -output = t0 * t1 or t0 + t1 - -t0 = most upstream according to spec -t1 = most downstream according to spec -=================== -*/ -static void DrawMultitextured( shaderCommands_t *input, int stage ) { - shaderStage_t *pStage; - - pStage = tess.xstages[stage]; - - GL_State( pStage->stateBits ); - - // this is an ugly hack to work around a GeForce driver - // bug with multitexture and clip planes - if ( backEnd.viewParms.isPortal ) { - qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - } - - // - // base - // - GL_SelectTexture( 0 ); - qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] ); - R_BindAnimatedImage( &pStage->bundle[0] ); - - // - // lightmap/secondary pass - // - GL_SelectTexture( 1 ); - qglEnable( GL_TEXTURE_2D ); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - if ( r_lightmap->integer ) { - GL_TexEnv( GL_REPLACE ); - } else { - GL_TexEnv( tess.shader->multitextureEnv ); - } - - qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[1] ); - - R_BindAnimatedImage( &pStage->bundle[1] ); - - R_DrawElements( input->numIndexes, input->indexes ); - - // - // disable texturing on TEXTURE1, then select TEXTURE0 - // - //qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - qglDisable( GL_TEXTURE_2D ); - - GL_SelectTexture( 0 ); -} - - - -/* -=================== -ProjectDlightTexture - -Perform dynamic lighting with another rendering pass -=================== -*/ -#if idppc_altivec -static void ProjectDlightTexture_altivec( void ) { - int i, l; - vec_t origin0, origin1, origin2; - float texCoords0, texCoords1; - vector float floatColorVec0, floatColorVec1; - vector float modulateVec, colorVec, zero; - vector short colorShort; - vector signed int colorInt; - vector unsigned char floatColorVecPerm, modulatePerm, colorChar; - vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff); - float *texCoords; - byte *colors; - byte clipBits[SHADER_MAX_VERTEXES]; - float texCoordsArray[SHADER_MAX_VERTEXES][2]; - byte colorArray[SHADER_MAX_VERTEXES][4]; - unsigned hitIndexes[SHADER_MAX_INDEXES]; - int numIndexes; - float scale; - float radius; - vec3_t floatColor; - float modulate = 0.0f; - - if ( !backEnd.refdef.num_dlights ) { - return; - } - - // There has to be a better way to do this so that floatColor - // and/or modulate are already 16-byte aligned. - floatColorVecPerm = vec_lvsl(0,(float *)floatColor); - modulatePerm = vec_lvsl(0,(float *)&modulate); - modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0); - zero = (vector float)vec_splat_s8(0); - - for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { - dlight_t *dl; - - if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light - } - texCoords = texCoordsArray[0]; - colors = colorArray[0]; - - dl = &backEnd.refdef.dlights[l]; - origin0 = dl->transformed[0]; - origin1 = dl->transformed[1]; - origin2 = dl->transformed[2]; - radius = dl->radius; - scale = 1.0f / radius; - - if(r_greyscale->integer) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = floatColor[1] = floatColor[2] = luminance; - } - else if(r_greyscale->value) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); - floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); - floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); - } - else - { - floatColor[0] = dl->color[0] * 255.0f; - floatColor[1] = dl->color[1] * 255.0f; - floatColor[2] = dl->color[2] * 255.0f; - } - floatColorVec0 = vec_ld(0, floatColor); - floatColorVec1 = vec_ld(11, floatColor); - floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm); - for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { - int clip = 0; - vec_t dist0, dist1, dist2; - - dist0 = origin0 - tess.xyz[i][0]; - dist1 = origin1 - tess.xyz[i][1]; - dist2 = origin2 - tess.xyz[i][2]; - - backEnd.pc.c_dlightVertexes++; - - texCoords0 = 0.5f + dist0 * scale; - texCoords1 = 0.5f + dist1 * scale; - - if( !r_dlightBacks->integer && - // dist . tess.normal[i] - ( dist0 * tess.normal[i][0] + - dist1 * tess.normal[i][1] + - dist2 * tess.normal[i][2] ) < 0.0f ) { - clip = 63; - } else { - if ( texCoords0 < 0.0f ) { - clip |= 1; - } else if ( texCoords0 > 1.0f ) { - clip |= 2; - } - if ( texCoords1 < 0.0f ) { - clip |= 4; - } else if ( texCoords1 > 1.0f ) { - clip |= 8; - } - texCoords[0] = texCoords0; - texCoords[1] = texCoords1; - - // modulate the strength based on the height and color - if ( dist2 > radius ) { - clip |= 16; - modulate = 0.0f; - } else if ( dist2 < -radius ) { - clip |= 32; - modulate = 0.0f; - } else { - dist2 = Q_fabs(dist2); - if ( dist2 < radius * 0.5f ) { - modulate = 1.0f; - } else { - modulate = 2.0f * (radius - dist2) * scale; - } - } - } - clipBits[i] = clip; - - modulateVec = vec_ld(0,(float *)&modulate); - modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm); - colorVec = vec_madd(floatColorVec0,modulateVec,zero); - colorInt = vec_cts(colorVec,0); // RGBx - colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx - colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx - colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 - vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color - } - - // build a list of triangles that need light - numIndexes = 0; - for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { - int a, b, c; - - a = tess.indexes[i]; - b = tess.indexes[i+1]; - c = tess.indexes[i+2]; - if ( clipBits[a] & clipBits[b] & clipBits[c] ) { - continue; // not lighted - } - hitIndexes[numIndexes] = a; - hitIndexes[numIndexes+1] = b; - hitIndexes[numIndexes+2] = c; - numIndexes += 3; - } - - if ( !numIndexes ) { - continue; - } - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); - - qglEnableClientState( GL_COLOR_ARRAY ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); - - GL_Bind( tr.dlightImage ); - // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light - // where they aren't rendered - if ( dl->additive ) { - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - else { - GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - R_DrawElements( numIndexes, hitIndexes ); - backEnd.pc.c_totalIndexes += numIndexes; - backEnd.pc.c_dlightIndexes += numIndexes; - } -} -#endif - - -static void ProjectDlightTexture_scalar( void ) { - int i, l; - vec3_t origin; - float *texCoords; - byte *colors; - byte clipBits[SHADER_MAX_VERTEXES]; - float texCoordsArray[SHADER_MAX_VERTEXES][2]; - byte colorArray[SHADER_MAX_VERTEXES][4]; - unsigned hitIndexes[SHADER_MAX_INDEXES]; - int numIndexes; - float scale; - float radius; - vec3_t floatColor; - float modulate = 0.0f; - - if ( !backEnd.refdef.num_dlights ) { - return; - } - - for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { - dlight_t *dl; - - if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light - } - texCoords = texCoordsArray[0]; - colors = colorArray[0]; - - dl = &backEnd.refdef.dlights[l]; - VectorCopy( dl->transformed, origin ); - radius = dl->radius; - scale = 1.0f / radius; - - if(r_greyscale->integer) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = floatColor[1] = floatColor[2] = luminance; - } - else if(r_greyscale->value) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); - floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); - floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); - } - else - { - floatColor[0] = dl->color[0] * 255.0f; - floatColor[1] = dl->color[1] * 255.0f; - floatColor[2] = dl->color[2] * 255.0f; - } - - for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { - int clip = 0; - vec3_t dist; - - VectorSubtract( origin, tess.xyz[i], dist ); - - backEnd.pc.c_dlightVertexes++; - - texCoords[0] = 0.5f + dist[0] * scale; - texCoords[1] = 0.5f + dist[1] * scale; - - if( !r_dlightBacks->integer && - // dist . tess.normal[i] - ( dist[0] * tess.normal[i][0] + - dist[1] * tess.normal[i][1] + - dist[2] * tess.normal[i][2] ) < 0.0f ) { - clip = 63; - } else { - if ( texCoords[0] < 0.0f ) { - clip |= 1; - } else if ( texCoords[0] > 1.0f ) { - clip |= 2; - } - if ( texCoords[1] < 0.0f ) { - clip |= 4; - } else if ( texCoords[1] > 1.0f ) { - clip |= 8; - } - texCoords[0] = texCoords[0]; - texCoords[1] = texCoords[1]; - - // modulate the strength based on the height and color - if ( dist[2] > radius ) { - clip |= 16; - modulate = 0.0f; - } else if ( dist[2] < -radius ) { - clip |= 32; - modulate = 0.0f; - } else { - dist[2] = Q_fabs(dist[2]); - if ( dist[2] < radius * 0.5f ) { - modulate = 1.0f; - } else { - modulate = 2.0f * (radius - dist[2]) * scale; - } - } - } - clipBits[i] = clip; - colors[0] = ri.ftol(floatColor[0] * modulate); - colors[1] = ri.ftol(floatColor[1] * modulate); - colors[2] = ri.ftol(floatColor[2] * modulate); - colors[3] = 255; - } - - // build a list of triangles that need light - numIndexes = 0; - for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { - int a, b, c; - - a = tess.indexes[i]; - b = tess.indexes[i+1]; - c = tess.indexes[i+2]; - if ( clipBits[a] & clipBits[b] & clipBits[c] ) { - continue; // not lighted - } - hitIndexes[numIndexes] = a; - hitIndexes[numIndexes+1] = b; - hitIndexes[numIndexes+2] = c; - numIndexes += 3; - } - - if ( !numIndexes ) { - continue; - } - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); - - qglEnableClientState( GL_COLOR_ARRAY ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); - - GL_Bind( tr.dlightImage ); - // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light - // where they aren't rendered - if ( dl->additive ) { - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - else { - GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - R_DrawElements( numIndexes, hitIndexes ); - backEnd.pc.c_totalIndexes += numIndexes; - backEnd.pc.c_dlightIndexes += numIndexes; - } -} - -static void ProjectDlightTexture( void ) { -#if idppc_altivec - if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. - ProjectDlightTexture_altivec(); - return; - } -#endif - ProjectDlightTexture_scalar(); -} - - -/* -=================== -RB_FogPass - -Blends a fog texture on top of everything else -=================== -*/ -static void RB_FogPass( void ) { - fog_t *fog; - int i; - - qglEnableClientState( GL_COLOR_ARRAY ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY); - qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); - - fog = tr.world->fogs + tess.fogNum; - - for ( i = 0; i < tess.numVertexes; i++ ) { - * ( int * )&tess.svars.colors[i] = fog->colorInt; - } - - RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] ); - - GL_Bind( tr.fogImage ); - - if ( tess.shader->fogPass == FP_EQUAL ) { - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); - } else { - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - } - - R_DrawElements( tess.numIndexes, tess.indexes ); -} - -/* -=============== -ComputeColors -=============== -*/ -static void ComputeColors( shaderStage_t *pStage ) -{ - int i; - - // - // rgbGen - // - switch ( pStage->rgbGen ) - { - case CGEN_IDENTITY: - Com_Memset( tess.svars.colors, 0xff, tess.numVertexes * 4 ); - break; - default: - case CGEN_IDENTITY_LIGHTING: - Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 ); - break; - case CGEN_LIGHTING_DIFFUSE: - RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); - break; - case CGEN_EXACT_VERTEX: - Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); - break; - case CGEN_CONST: - for ( i = 0; i < tess.numVertexes; i++ ) { - *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor; - } - break; - case CGEN_VERTEX: - if ( tr.identityLight == 1 ) - { - Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); - } - else - { - for ( i = 0; i < tess.numVertexes; i++ ) - { - tess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight; - tess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight; - tess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight; - tess.svars.colors[i][3] = tess.vertexColors[i][3]; - } - } - break; - case CGEN_ONE_MINUS_VERTEX: - if ( tr.identityLight == 1 ) - { - for ( i = 0; i < tess.numVertexes; i++ ) - { - tess.svars.colors[i][0] = 255 - tess.vertexColors[i][0]; - tess.svars.colors[i][1] = 255 - tess.vertexColors[i][1]; - tess.svars.colors[i][2] = 255 - tess.vertexColors[i][2]; - } - } - else - { - for ( i = 0; i < tess.numVertexes; i++ ) - { - tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight; - tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight; - tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight; - } - } - break; - case CGEN_FOG: - { - fog_t *fog; - - fog = tr.world->fogs + tess.fogNum; - - for ( i = 0; i < tess.numVertexes; i++ ) { - * ( int * )&tess.svars.colors[i] = fog->colorInt; - } - } - break; - case CGEN_WAVEFORM: - RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors ); - break; - case CGEN_ENTITY: - RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors ); - break; - case CGEN_ONE_MINUS_ENTITY: - RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); - break; - } - - // - // alphaGen - // - switch ( pStage->alphaGen ) - { - case AGEN_SKIP: - break; - case AGEN_IDENTITY: - if ( pStage->rgbGen != CGEN_IDENTITY ) { - if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) || - pStage->rgbGen != CGEN_VERTEX ) { - for ( i = 0; i < tess.numVertexes; i++ ) { - tess.svars.colors[i][3] = 0xff; - } - } - } - break; - case AGEN_CONST: - if ( pStage->rgbGen != CGEN_CONST ) { - for ( i = 0; i < tess.numVertexes; i++ ) { - tess.svars.colors[i][3] = pStage->constantColor[3]; - } - } - break; - case AGEN_WAVEFORM: - RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors ); - break; - case AGEN_LIGHTING_SPECULAR: - RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors ); - break; - case AGEN_ENTITY: - RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors ); - break; - case AGEN_ONE_MINUS_ENTITY: - RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); - break; - case AGEN_VERTEX: - if ( pStage->rgbGen != CGEN_VERTEX ) { - for ( i = 0; i < tess.numVertexes; i++ ) { - tess.svars.colors[i][3] = tess.vertexColors[i][3]; - } - } - break; - case AGEN_ONE_MINUS_VERTEX: - for ( i = 0; i < tess.numVertexes; i++ ) - { - tess.svars.colors[i][3] = 255 - tess.vertexColors[i][3]; - } - break; - case AGEN_PORTAL: - { - unsigned char alpha; - - for ( i = 0; i < tess.numVertexes; i++ ) - { - float len; - vec3_t v; - - VectorSubtract( tess.xyz[i], backEnd.viewParms.or.origin, v ); - len = VectorLength( v ); - - len /= tess.shader->portalRange; - - if ( len < 0 ) - { - alpha = 0; - } - else if ( len > 1 ) - { - alpha = 0xff; - } - else - { - alpha = len * 0xff; - } - - tess.svars.colors[i][3] = alpha; - } - } - break; - } - - // - // fog adjustment for colors to fade out as fog increases - // - if ( tess.fogNum ) - { - switch ( pStage->adjustColorsForFog ) - { - case ACFF_MODULATE_RGB: - RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors ); - break; - case ACFF_MODULATE_ALPHA: - RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors ); - break; - case ACFF_MODULATE_RGBA: - RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors ); - break; - case ACFF_NONE: - break; - } - } - - // if in greyscale rendering mode turn all color values into greyscale. - if(r_greyscale->integer) - { - int scale; - for(i = 0; i < tess.numVertexes; i++) - { - scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); - tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; - } - } - else if(r_greyscale->value) - { - float scale; - - for(i = 0; i < tess.numVertexes; i++) - { - scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); - tess.svars.colors[i][0] = LERP(tess.svars.colors[i][0], scale, r_greyscale->value); - tess.svars.colors[i][1] = LERP(tess.svars.colors[i][1], scale, r_greyscale->value); - tess.svars.colors[i][2] = LERP(tess.svars.colors[i][2], scale, r_greyscale->value); - } - } -} - -/* -=============== -ComputeTexCoords -=============== -*/ -static void ComputeTexCoords( shaderStage_t *pStage ) { - int i; - int b; - - for ( b = 0; b < NUM_TEXTURE_BUNDLES; b++ ) { - int tm; - - // - // generate the texture coordinates - // - switch ( pStage->bundle[b].tcGen ) - { - case TCGEN_IDENTITY: - Com_Memset( tess.svars.texcoords[b], 0, sizeof( float ) * 2 * tess.numVertexes ); - break; - case TCGEN_TEXTURE: - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - tess.svars.texcoords[b][i][0] = tess.texCoords[i][0][0]; - tess.svars.texcoords[b][i][1] = tess.texCoords[i][0][1]; - } - break; - case TCGEN_LIGHTMAP: - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - tess.svars.texcoords[b][i][0] = tess.texCoords[i][1][0]; - tess.svars.texcoords[b][i][1] = tess.texCoords[i][1][1]; - } - break; - case TCGEN_VECTOR: - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - tess.svars.texcoords[b][i][0] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[0] ); - tess.svars.texcoords[b][i][1] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[1] ); - } - break; - case TCGEN_FOG: - RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[b] ); - break; - case TCGEN_ENVIRONMENT_MAPPED: - RB_CalcEnvironmentTexCoords( ( float * ) tess.svars.texcoords[b] ); - break; - case TCGEN_BAD: - return; - } - - // - // alter texture coordinates - // - for ( tm = 0; tm < pStage->bundle[b].numTexMods ; tm++ ) { - switch ( pStage->bundle[b].texMods[tm].type ) - { - case TMOD_NONE: - tm = TR_MAX_TEXMODS; // break out of for loop - break; - - case TMOD_TURBULENT: - RB_CalcTurbulentTexCoords( &pStage->bundle[b].texMods[tm].wave, - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_ENTITY_TRANSLATE: - RB_CalcScrollTexCoords( backEnd.currentEntity->e.shaderTexCoord, - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_SCROLL: - RB_CalcScrollTexCoords( pStage->bundle[b].texMods[tm].scroll, - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_SCALE: - RB_CalcScaleTexCoords( pStage->bundle[b].texMods[tm].scale, - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_STRETCH: - RB_CalcStretchTexCoords( &pStage->bundle[b].texMods[tm].wave, - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_TRANSFORM: - RB_CalcTransformTexCoords( &pStage->bundle[b].texMods[tm], - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_ROTATE: - RB_CalcRotateTexCoords( pStage->bundle[b].texMods[tm].rotateSpeed, - ( float * ) tess.svars.texcoords[b] ); - break; - - default: - ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'", pStage->bundle[b].texMods[tm].type, tess.shader->name ); - break; - } - } - } -} - -/* -** RB_IterateStagesGeneric -*/ -static void RB_IterateStagesGeneric( shaderCommands_t *input ) -{ - int stage; - - for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) - { - shaderStage_t *pStage = tess.xstages[stage]; - - if ( !pStage ) - { - break; - } - - ComputeColors( pStage ); - ComputeTexCoords( pStage ); - - if ( !setArraysOnce ) - { - qglEnableClientState( GL_COLOR_ARRAY ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors ); - } - - // - // do multitexture - // - if ( pStage->bundle[1].image[0] != 0 ) - { - DrawMultitextured( input, stage ); - } - else - { - if ( !setArraysOnce ) - { - qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] ); - } - - // - // set state - // - R_BindAnimatedImage( &pStage->bundle[0] ); - - GL_State( pStage->stateBits ); - - // - // draw - // - R_DrawElements( input->numIndexes, input->indexes ); - } - // allow skipping out to show just lightmaps during development - if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) - { - break; - } - } -} - - -/* -** RB_StageIteratorGeneric -*/ -void RB_StageIteratorGeneric( void ) -{ - shaderCommands_t *input; - shader_t *shader; - - input = &tess; - shader = input->shader; - - RB_DeformTessGeometry(); - - // - // log this call - // - if ( r_logFile->integer ) - { - // don't just call LogComment, or we will get - // a call to va() every frame! - GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) ); - } - - // - // set face culling appropriately - // - GL_Cull( shader->cullType ); - - // set polygon offset if necessary - if ( shader->polygonOffset ) - { - qglEnable( GL_POLYGON_OFFSET_FILL ); - qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); - } - - // - // if there is only a single pass then we can enable color - // and texture arrays before we compile, otherwise we need - // to avoid compiling those arrays since they will change - // during multipass rendering - // - if ( tess.numPasses > 1 || shader->multitextureEnv ) - { - setArraysOnce = qfalse; - qglDisableClientState (GL_COLOR_ARRAY); - qglDisableClientState (GL_TEXTURE_COORD_ARRAY); - } - else - { - setArraysOnce = qtrue; - - qglEnableClientState( GL_COLOR_ARRAY); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY); - qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); - } - - // - // lock XYZ - // - qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD - if (qglLockArraysEXT) - { - qglLockArraysEXT(0, input->numVertexes); - GLimp_LogComment( "glLockArraysEXT\n" ); - } - - // - // enable color and texcoord arrays after the lock if necessary - // - if ( !setArraysOnce ) - { - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - qglEnableClientState( GL_COLOR_ARRAY ); - } - - // - // call shader function - // - RB_IterateStagesGeneric( input ); - - // - // now do any dynamic lighting needed - // - if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE - && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { - ProjectDlightTexture(); - } - - // - // now do fog - // - if ( tess.fogNum && tess.shader->fogPass ) { - RB_FogPass(); - } - - // - // unlock arrays - // - if (qglUnlockArraysEXT) - { - qglUnlockArraysEXT(); - GLimp_LogComment( "glUnlockArraysEXT\n" ); - } - - // - // reset polygon offset - // - if ( shader->polygonOffset ) - { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } -} - - -/* -** RB_StageIteratorVertexLitTexture -*/ -void RB_StageIteratorVertexLitTexture( void ) -{ - shaderCommands_t *input; - shader_t *shader; - - input = &tess; - shader = input->shader; - - // - // compute colors - // - RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); - - // - // log this call - // - if ( r_logFile->integer ) - { - // don't just call LogComment, or we will get - // a call to va() every frame! - GLimp_LogComment( va("--- RB_StageIteratorVertexLitTexturedUnfogged( %s ) ---\n", tess.shader->name) ); - } - - // - // set face culling appropriately - // - GL_Cull( shader->cullType ); - - // - // set arrays and lock - // - qglEnableClientState( GL_COLOR_ARRAY); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY); - - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); - qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] ); - qglVertexPointer (3, GL_FLOAT, 16, input->xyz); - - if ( qglLockArraysEXT ) - { - qglLockArraysEXT(0, input->numVertexes); - GLimp_LogComment( "glLockArraysEXT\n" ); - } - - // - // call special shade routine - // - R_BindAnimatedImage( &tess.xstages[0]->bundle[0] ); - GL_State( tess.xstages[0]->stateBits ); - R_DrawElements( input->numIndexes, input->indexes ); - - // - // now do any dynamic lighting needed - // - if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) { - ProjectDlightTexture(); - } - - // - // now do fog - // - if ( tess.fogNum && tess.shader->fogPass ) { - RB_FogPass(); - } - - // - // unlock arrays - // - if (qglUnlockArraysEXT) - { - qglUnlockArraysEXT(); - GLimp_LogComment( "glUnlockArraysEXT\n" ); - } -} - -//define REPLACE_MODE - -void RB_StageIteratorLightmappedMultitexture( void ) { - shaderCommands_t *input; - shader_t *shader; - - input = &tess; - shader = input->shader; - - // - // log this call - // - if ( r_logFile->integer ) { - // don't just call LogComment, or we will get - // a call to va() every frame! - GLimp_LogComment( va("--- RB_StageIteratorLightmappedMultitexture( %s ) ---\n", tess.shader->name) ); - } - - // - // set face culling appropriately - // - GL_Cull( shader->cullType ); - - // - // set color, pointers, and lock - // - GL_State( GLS_DEFAULT ); - qglVertexPointer( 3, GL_FLOAT, 16, input->xyz ); - -#ifdef REPLACE_MODE - qglDisableClientState( GL_COLOR_ARRAY ); - qglColor3f( 1, 1, 1 ); - qglShadeModel( GL_FLAT ); -#else - qglEnableClientState( GL_COLOR_ARRAY ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.constantColor255 ); -#endif - - // - // select base stage - // - GL_SelectTexture( 0 ); - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - R_BindAnimatedImage( &tess.xstages[0]->bundle[0] ); - qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] ); - - // - // configure second stage - // - GL_SelectTexture( 1 ); - qglEnable( GL_TEXTURE_2D ); - if ( r_lightmap->integer ) { - GL_TexEnv( GL_REPLACE ); - } else { - GL_TexEnv( GL_MODULATE ); - } - R_BindAnimatedImage( &tess.xstages[0]->bundle[1] ); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][1] ); - - // - // lock arrays - // - if ( qglLockArraysEXT ) { - qglLockArraysEXT(0, input->numVertexes); - GLimp_LogComment( "glLockArraysEXT\n" ); - } - - R_DrawElements( input->numIndexes, input->indexes ); - - // - // disable texturing on TEXTURE1, then select TEXTURE0 - // - qglDisable( GL_TEXTURE_2D ); - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - - GL_SelectTexture( 0 ); -#ifdef REPLACE_MODE - GL_TexEnv( GL_MODULATE ); - qglShadeModel( GL_SMOOTH ); -#endif - - // - // now do any dynamic lighting needed - // - if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) { - ProjectDlightTexture(); - } - - // - // now do fog - // - if ( tess.fogNum && tess.shader->fogPass ) { - RB_FogPass(); - } - - // - // unlock arrays - // - if ( qglUnlockArraysEXT ) { - qglUnlockArraysEXT(); - GLimp_LogComment( "glUnlockArraysEXT\n" ); - } -} - -/* -** RB_EndSurface -*/ -void RB_EndSurface( void ) { - shaderCommands_t *input; - - input = &tess; - - if (input->numIndexes == 0) { - return; - } - - if (input->indexes[SHADER_MAX_INDEXES-1] != 0) { - ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit"); - } - if (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) { - ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit"); - } - - if ( tess.shader == tr.shadowShader ) { - RB_ShadowTessEnd(); - return; - } - - // for debugging of sort order issues, stop rendering after a given sort value - if ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) { - return; - } - - // - // update performance counters - // - backEnd.pc.c_shaders++; - backEnd.pc.c_vertexes += tess.numVertexes; - backEnd.pc.c_indexes += tess.numIndexes; - backEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses; - - // - // call off to shader specific tess end function - // - tess.currentStageIteratorFunc(); - - // - // draw debugging stuff - // - if ( r_showtris->integer ) { - DrawTris (input); - } - if ( r_shownormals->integer ) { - DrawNormals (input); - } - // clear shader so we can tell we don't have any unclosed surfaces - tess.numIndexes = 0; - - GLimp_LogComment( "----------\n" ); -} - diff --git a/code/renderergl1/tr_shade_calc.c b/code/renderergl1/tr_shade_calc.c deleted file mode 100644 index e8f43e4f1f..0000000000 --- a/code/renderergl1/tr_shade_calc.c +++ /dev/null @@ -1,1216 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_shade_calc.c - -#include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - - -#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ri.ftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) - -static float *TableForFunc( genFunc_t func ) -{ - switch ( func ) - { - case GF_SIN: - return tr.sinTable; - case GF_TRIANGLE: - return tr.triangleTable; - case GF_SQUARE: - return tr.squareTable; - case GF_SAWTOOTH: - return tr.sawToothTable; - case GF_INVERSE_SAWTOOTH: - return tr.inverseSawToothTable; - case GF_NONE: - default: - break; - } - - ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'", func, tess.shader->name ); - return NULL; -} - -/* -** EvalWaveForm -** -** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly -*/ -static float EvalWaveForm( const waveForm_t *wf ) -{ - float *table; - - table = TableForFunc( wf->func ); - - return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency ); -} - -static float EvalWaveFormClamped( const waveForm_t *wf ) -{ - float glow = EvalWaveForm( wf ); - - if ( glow < 0 ) - { - return 0; - } - - if ( glow > 1 ) - { - return 1; - } - - return glow; -} - -/* -** RB_CalcStretchTexCoords -*/ -void RB_CalcStretchTexCoords( const waveForm_t *wf, float *st ) -{ - float p; - texModInfo_t tmi; - - p = 1.0f / EvalWaveForm( wf ); - - tmi.matrix[0][0] = p; - tmi.matrix[1][0] = 0; - tmi.translate[0] = 0.5f - 0.5f * p; - - tmi.matrix[0][1] = 0; - tmi.matrix[1][1] = p; - tmi.translate[1] = 0.5f - 0.5f * p; - - RB_CalcTransformTexCoords( &tmi, st ); -} - -/* -==================================================================== - -DEFORMATIONS - -==================================================================== -*/ - -/* -======================== -RB_CalcDeformVertexes - -======================== -*/ -void RB_CalcDeformVertexes( deformStage_t *ds ) -{ - int i; - vec3_t offset; - float scale; - float *xyz = ( float * ) tess.xyz; - float *normal = ( float * ) tess.normal; - float *table; - - if ( ds->deformationWave.frequency == 0 ) - { - scale = EvalWaveForm( &ds->deformationWave ); - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) - { - VectorScale( normal, scale, offset ); - - xyz[0] += offset[0]; - xyz[1] += offset[1]; - xyz[2] += offset[2]; - } - } - else - { - table = TableForFunc( ds->deformationWave.func ); - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) - { - float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread; - - scale = WAVEVALUE( table, ds->deformationWave.base, - ds->deformationWave.amplitude, - ds->deformationWave.phase + off, - ds->deformationWave.frequency ); - - VectorScale( normal, scale, offset ); - - xyz[0] += offset[0]; - xyz[1] += offset[1]; - xyz[2] += offset[2]; - } - } -} - -/* -========================= -RB_CalcDeformNormals - -Wiggle the normals for wavy environment mapping -========================= -*/ -void RB_CalcDeformNormals( deformStage_t *ds ) { - int i; - float scale; - float *xyz = ( float * ) tess.xyz; - float *normal = ( float * ) tess.normal; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) { - scale = 0.98f; - scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - normal[ 0 ] += ds->deformationWave.amplitude * scale; - - scale = 0.98f; - scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - normal[ 1 ] += ds->deformationWave.amplitude * scale; - - scale = 0.98f; - scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - normal[ 2 ] += ds->deformationWave.amplitude * scale; - - VectorNormalizeFast( normal ); - } -} - -/* -======================== -RB_CalcBulgeVertexes - -======================== -*/ -void RB_CalcBulgeVertexes( deformStage_t *ds ) { - int i; - const float *st = ( const float * ) tess.texCoords[0]; - float *xyz = ( float * ) tess.xyz; - float *normal = ( float * ) tess.normal; - float now; - - now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) { - int off; - float scale; - - off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now ); - - scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight; - - xyz[0] += normal[0] * scale; - xyz[1] += normal[1] * scale; - xyz[2] += normal[2] * scale; - } -} - - -/* -====================== -RB_CalcMoveVertexes - -A deformation that can move an entire surface along a wave path -====================== -*/ -void RB_CalcMoveVertexes( deformStage_t *ds ) { - int i; - float *xyz; - float *table; - float scale; - vec3_t offset; - - table = TableForFunc( ds->deformationWave.func ); - - scale = WAVEVALUE( table, ds->deformationWave.base, - ds->deformationWave.amplitude, - ds->deformationWave.phase, - ds->deformationWave.frequency ); - - VectorScale( ds->moveVector, scale, offset ); - - xyz = ( float * ) tess.xyz; - for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) { - VectorAdd( xyz, offset, xyz ); - } -} - - -/* -============= -DeformText - -Change a polygon into a bunch of text polygons -============= -*/ -void DeformText( const char *text ) { - int i; - vec3_t origin, width, height; - int len; - int ch; - byte color[4]; - float bottom, top; - vec3_t mid; - - height[0] = 0; - height[1] = 0; - height[2] = -1; - CrossProduct( tess.normal[0], height, width ); - - // find the midpoint of the box - VectorClear( mid ); - bottom = 999999; - top = -999999; - for ( i = 0 ; i < 4 ; i++ ) { - VectorAdd( tess.xyz[i], mid, mid ); - if ( tess.xyz[i][2] < bottom ) { - bottom = tess.xyz[i][2]; - } - if ( tess.xyz[i][2] > top ) { - top = tess.xyz[i][2]; - } - } - VectorScale( mid, 0.25f, origin ); - - // determine the individual character size - height[0] = 0; - height[1] = 0; - height[2] = ( top - bottom ) * 0.5f; - - VectorScale( width, height[2] * -0.75f, width ); - - // determine the starting position - len = strlen( text ); - VectorMA( origin, (len-1), width, origin ); - - // clear the shader indexes - tess.numIndexes = 0; - tess.numVertexes = 0; - - color[0] = color[1] = color[2] = color[3] = 255; - - // draw each character - for ( i = 0 ; i < len ; i++ ) { - ch = text[i]; - ch &= 255; - - if ( ch != ' ' ) { - int row, col; - float frow, fcol, size; - - row = ch>>4; - col = ch&15; - - frow = row*0.0625f; - fcol = col*0.0625f; - size = 0.0625f; - - RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size ); - } - VectorMA( origin, -2, width, origin ); - } -} - -/* -================== -GlobalVectorToLocal -================== -*/ -static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) { - out[0] = DotProduct( in, backEnd.or.axis[0] ); - out[1] = DotProduct( in, backEnd.or.axis[1] ); - out[2] = DotProduct( in, backEnd.or.axis[2] ); -} - -/* -===================== -AutospriteDeform - -Assuming all the triangles for this shader are independant -quads, rebuild them as forward facing sprites -===================== -*/ -static void AutospriteDeform( void ) { - int i; - int oldVerts; - float *xyz; - vec3_t mid, delta; - float radius; - vec3_t left, up; - vec3_t leftDir, upDir; - - if ( tess.numVertexes & 3 ) { - ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count\n", tess.shader->name ); - } - if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) { - ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count\n", tess.shader->name ); - } - - oldVerts = tess.numVertexes; - tess.numVertexes = 0; - tess.numIndexes = 0; - - if ( backEnd.currentEntity != &tr.worldEntity ) { - GlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir ); - GlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir ); - } else { - VectorCopy( backEnd.viewParms.or.axis[1], leftDir ); - VectorCopy( backEnd.viewParms.or.axis[2], upDir ); - } - - for ( i = 0 ; i < oldVerts ; i+=4 ) { - // find the midpoint - xyz = tess.xyz[i]; - - mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]); - mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]); - mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]); - - VectorSubtract( xyz, mid, delta ); - radius = VectorLength( delta ) * 0.707f; // / sqrt(2) - - VectorScale( leftDir, radius, left ); - VectorScale( upDir, radius, up ); - - if ( backEnd.viewParms.isMirror ) { - VectorSubtract( vec3_origin, left, left ); - } - - // compensate for scale in the axes if necessary - if ( backEnd.currentEntity->e.nonNormalizedAxes ) { - float axisLength; - axisLength = VectorLength( backEnd.currentEntity->e.axis[0] ); - if ( !axisLength ) { - axisLength = 0; - } else { - axisLength = 1.0f / axisLength; - } - VectorScale(left, axisLength, left); - VectorScale(up, axisLength, up); - } - - RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] ); - } -} - - -/* -===================== -Autosprite2Deform - -Autosprite2 will pivot a rectangular quad along the center of its long axis -===================== -*/ -int edgeVerts[6][2] = { - { 0, 1 }, - { 0, 2 }, - { 0, 3 }, - { 1, 2 }, - { 1, 3 }, - { 2, 3 } -}; - -static void Autosprite2Deform( void ) { - int i, j, k; - int indexes; - float *xyz; - vec3_t forward; - - if ( tess.numVertexes & 3 ) { - ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count", tess.shader->name ); - } - if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) { - ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count", tess.shader->name ); - } - - if ( backEnd.currentEntity != &tr.worldEntity ) { - GlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward ); - } else { - VectorCopy( backEnd.viewParms.or.axis[0], forward ); - } - - // this is a lot of work for two triangles... - // we could precalculate a lot of it is an issue, but it would mess up - // the shader abstraction - for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) { - float lengths[2]; - int nums[2]; - vec3_t mid[2]; - vec3_t major, minor; - float *v1, *v2; - - // find the midpoint - xyz = tess.xyz[i]; - - // identify the two shortest edges - nums[0] = nums[1] = 0; - lengths[0] = lengths[1] = 999999; - - for ( j = 0 ; j < 6 ; j++ ) { - float l; - vec3_t temp; - - v1 = xyz + 4 * edgeVerts[j][0]; - v2 = xyz + 4 * edgeVerts[j][1]; - - VectorSubtract( v1, v2, temp ); - - l = DotProduct( temp, temp ); - if ( l < lengths[0] ) { - nums[1] = nums[0]; - lengths[1] = lengths[0]; - nums[0] = j; - lengths[0] = l; - } else if ( l < lengths[1] ) { - nums[1] = j; - lengths[1] = l; - } - } - - for ( j = 0 ; j < 2 ; j++ ) { - v1 = xyz + 4 * edgeVerts[nums[j]][0]; - v2 = xyz + 4 * edgeVerts[nums[j]][1]; - - mid[j][0] = 0.5f * (v1[0] + v2[0]); - mid[j][1] = 0.5f * (v1[1] + v2[1]); - mid[j][2] = 0.5f * (v1[2] + v2[2]); - } - - // find the vector of the major axis - VectorSubtract( mid[1], mid[0], major ); - - // cross this with the view direction to get minor axis - CrossProduct( major, forward, minor ); - VectorNormalize( minor ); - - // re-project the points - for ( j = 0 ; j < 2 ; j++ ) { - float l; - - v1 = xyz + 4 * edgeVerts[nums[j]][0]; - v2 = xyz + 4 * edgeVerts[nums[j]][1]; - - l = 0.5 * sqrt( lengths[j] ); - - // we need to see which direction this edge - // is used to determine direction of projection - for ( k = 0 ; k < 5 ; k++ ) { - if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0] - && tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) { - break; - } - } - - if ( k == 5 ) { - VectorMA( mid[j], l, minor, v1 ); - VectorMA( mid[j], -l, minor, v2 ); - } else { - VectorMA( mid[j], -l, minor, v1 ); - VectorMA( mid[j], l, minor, v2 ); - } - } - } -} - - -/* -===================== -RB_DeformTessGeometry - -===================== -*/ -void RB_DeformTessGeometry( void ) { - int i; - deformStage_t *ds; - - for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) { - ds = &tess.shader->deforms[ i ]; - - switch ( ds->deformation ) { - case DEFORM_NONE: - break; - case DEFORM_NORMALS: - RB_CalcDeformNormals( ds ); - break; - case DEFORM_WAVE: - RB_CalcDeformVertexes( ds ); - break; - case DEFORM_BULGE: - RB_CalcBulgeVertexes( ds ); - break; - case DEFORM_MOVE: - RB_CalcMoveVertexes( ds ); - break; - case DEFORM_PROJECTION_SHADOW: - RB_ProjectionShadowDeform(); - break; - case DEFORM_AUTOSPRITE: - AutospriteDeform(); - break; - case DEFORM_AUTOSPRITE2: - Autosprite2Deform(); - break; - case DEFORM_TEXT0: - case DEFORM_TEXT1: - case DEFORM_TEXT2: - case DEFORM_TEXT3: - case DEFORM_TEXT4: - case DEFORM_TEXT5: - case DEFORM_TEXT6: - case DEFORM_TEXT7: - DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] ); - break; - } - } -} - -/* -==================================================================== - -COLORS - -==================================================================== -*/ - - -/* -** RB_CalcColorFromEntity -*/ -void RB_CalcColorFromEntity( unsigned char *dstColors ) -{ - int i; - int *pColors = ( int * ) dstColors; - int c; - - if ( !backEnd.currentEntity ) - return; - - c = * ( int * ) backEnd.currentEntity->e.shaderRGBA; - - for ( i = 0; i < tess.numVertexes; i++, pColors++ ) - { - *pColors = c; - } -} - -/* -** RB_CalcColorFromOneMinusEntity -*/ -void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors ) -{ - int i; - int *pColors = ( int * ) dstColors; - unsigned char invModulate[4]; - int c; - - if ( !backEnd.currentEntity ) - return; - - invModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0]; - invModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1]; - invModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2]; - invModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3]; // this trashes alpha, but the AGEN block fixes it - - c = * ( int * ) invModulate; - - for ( i = 0; i < tess.numVertexes; i++, pColors++ ) - { - *pColors = c; - } -} - -/* -** RB_CalcAlphaFromEntity -*/ -void RB_CalcAlphaFromEntity( unsigned char *dstColors ) -{ - int i; - - if ( !backEnd.currentEntity ) - return; - - dstColors += 3; - - for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) - { - *dstColors = backEnd.currentEntity->e.shaderRGBA[3]; - } -} - -/* -** RB_CalcAlphaFromOneMinusEntity -*/ -void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors ) -{ - int i; - - if ( !backEnd.currentEntity ) - return; - - dstColors += 3; - - for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) - { - *dstColors = 0xff - backEnd.currentEntity->e.shaderRGBA[3]; - } -} - -/* -** RB_CalcWaveColor -*/ -void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors ) -{ - int i; - int v; - float glow; - int *colors = ( int * ) dstColors; - byte color[4]; - - - if ( wf->func == GF_NOISE ) { - glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude; - } else { - glow = EvalWaveForm( wf ) * tr.identityLight; - } - - if ( glow < 0 ) { - glow = 0; - } - else if ( glow > 1 ) { - glow = 1; - } - - v = ri.ftol(255 * glow); - color[0] = color[1] = color[2] = v; - color[3] = 255; - v = *(int *)color; - - for ( i = 0; i < tess.numVertexes; i++, colors++ ) { - *colors = v; - } -} - -/* -** RB_CalcWaveAlpha -*/ -void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors ) -{ - int i; - int v; - float glow; - - glow = EvalWaveFormClamped( wf ); - - v = 255 * glow; - - for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) - { - dstColors[3] = v; - } -} - -/* -** RB_CalcModulateColorsByFog -*/ -void RB_CalcModulateColorsByFog( unsigned char *colors ) { - int i; - float texCoords[SHADER_MAX_VERTEXES][2]; - - // calculate texcoords so we can derive density - // this is not wasted, because it would only have - // been previously called if the surface was opaque - RB_CalcFogTexCoords( texCoords[0] ); - - for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { - float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); - colors[0] *= f; - colors[1] *= f; - colors[2] *= f; - } -} - -/* -** RB_CalcModulateAlphasByFog -*/ -void RB_CalcModulateAlphasByFog( unsigned char *colors ) { - int i; - float texCoords[SHADER_MAX_VERTEXES][2]; - - // calculate texcoords so we can derive density - // this is not wasted, because it would only have - // been previously called if the surface was opaque - RB_CalcFogTexCoords( texCoords[0] ); - - for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { - float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); - colors[3] *= f; - } -} - -/* -** RB_CalcModulateRGBAsByFog -*/ -void RB_CalcModulateRGBAsByFog( unsigned char *colors ) { - int i; - float texCoords[SHADER_MAX_VERTEXES][2]; - - // calculate texcoords so we can derive density - // this is not wasted, because it would only have - // been previously called if the surface was opaque - RB_CalcFogTexCoords( texCoords[0] ); - - for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { - float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); - colors[0] *= f; - colors[1] *= f; - colors[2] *= f; - colors[3] *= f; - } -} - - -/* -==================================================================== - -TEX COORDS - -==================================================================== -*/ - -/* -======================== -RB_CalcFogTexCoords - -To do the clipped fog plane really correctly, we should use -projected textures, but I don't trust the drivers and it -doesn't fit our shader data. -======================== -*/ -void RB_CalcFogTexCoords( float *st ) { - int i; - float *v; - float s, t; - float eyeT; - qboolean eyeOutside; - fog_t *fog; - vec3_t local; - vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - - fog = tr.world->fogs + tess.fogNum; - - // all fogging distance is based on world Z units - VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); - fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; - fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; - fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; - fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); - - // scale the fog vectors based on the fog's thickness - fogDistanceVector[0] *= fog->tcScale; - fogDistanceVector[1] *= fog->tcScale; - fogDistanceVector[2] *= fog->tcScale; - fogDistanceVector[3] *= fog->tcScale; - - // rotate the gradient vector for this orientation - if ( fog->hasSurface ) { - fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + - fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; - fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + - fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; - fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + - fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; - fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); - - eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; - } else { - eyeT = 1; // non-surface fog always has eye inside - } - - // see if the viewpoint is outside - // this is needed for clipping distance even for constant fog - - if ( eyeT < 0 ) { - eyeOutside = qtrue; - } else { - eyeOutside = qfalse; - } - - fogDistanceVector[3] += 1.0/512; - - // calculate density for each point - for (i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4) { - // calculate the length in fog - s = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3]; - t = DotProduct( v, fogDepthVector ) + fogDepthVector[3]; - - // partially clipped fogs use the T axis - if ( eyeOutside ) { - if ( t < 1.0 ) { - t = 1.0/32; // point is outside, so no fogging - } else { - t = 1.0/32 + 30.0/32 * t / ( t - eyeT ); // cut the distance at the fog plane - } - } else { - if ( t < 0 ) { - t = 1.0/32; // point is outside, so no fogging - } else { - t = 31.0/32; - } - } - - st[0] = s; - st[1] = t; - st += 2; - } -} - - - -/* -** RB_CalcEnvironmentTexCoords -*/ -void RB_CalcEnvironmentTexCoords( float *st ) -{ - int i; - float *v, *normal; - vec3_t viewer, reflected; - float d; - - v = tess.xyz[0]; - normal = tess.normal[0]; - - for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) - { - VectorSubtract (backEnd.or.viewOrigin, v, viewer); - VectorNormalizeFast (viewer); - - d = DotProduct (normal, viewer); - - reflected[0] = normal[0]*2*d - viewer[0]; - reflected[1] = normal[1]*2*d - viewer[1]; - reflected[2] = normal[2]*2*d - viewer[2]; - - st[0] = 0.5 + reflected[1] * 0.5; - st[1] = 0.5 - reflected[2] * 0.5; - } -} - -/* -** RB_CalcTurbulentTexCoords -*/ -void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st ) -{ - int i; - float now; - - now = ( wf->phase + tess.shaderTime * wf->frequency ); - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - float s = st[0]; - float t = st[1]; - - st[0] = s + tr.sinTable[ ( ( int ) ( ( ( tess.xyz[i][0] + tess.xyz[i][2] )* 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; - st[1] = t + tr.sinTable[ ( ( int ) ( ( tess.xyz[i][1] * 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; - } -} - -/* -** RB_CalcScaleTexCoords -*/ -void RB_CalcScaleTexCoords( const float scale[2], float *st ) -{ - int i; - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - st[0] *= scale[0]; - st[1] *= scale[1]; - } -} - -/* -** RB_CalcScrollTexCoords -*/ -void RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st ) -{ - int i; - float timeScale = tess.shaderTime; - float adjustedScrollS, adjustedScrollT; - - adjustedScrollS = scrollSpeed[0] * timeScale; - adjustedScrollT = scrollSpeed[1] * timeScale; - - // clamp so coordinates don't continuously get larger, causing problems - // with hardware limits - adjustedScrollS = adjustedScrollS - floor( adjustedScrollS ); - adjustedScrollT = adjustedScrollT - floor( adjustedScrollT ); - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - st[0] += adjustedScrollS; - st[1] += adjustedScrollT; - } -} - -/* -** RB_CalcTransformTexCoords -*/ -void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st ) -{ - int i; - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - float s = st[0]; - float t = st[1]; - - st[0] = s * tmi->matrix[0][0] + t * tmi->matrix[1][0] + tmi->translate[0]; - st[1] = s * tmi->matrix[0][1] + t * tmi->matrix[1][1] + tmi->translate[1]; - } -} - -/* -** RB_CalcRotateTexCoords -*/ -void RB_CalcRotateTexCoords( float degsPerSecond, float *st ) -{ - float timeScale = tess.shaderTime; - float degs; - int index; - float sinValue, cosValue; - texModInfo_t tmi; - - degs = -degsPerSecond * timeScale; - index = degs * ( FUNCTABLE_SIZE / 360.0f ); - - sinValue = tr.sinTable[ index & FUNCTABLE_MASK ]; - cosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ]; - - tmi.matrix[0][0] = cosValue; - tmi.matrix[1][0] = -sinValue; - tmi.translate[0] = 0.5 - 0.5 * cosValue + 0.5 * sinValue; - - tmi.matrix[0][1] = sinValue; - tmi.matrix[1][1] = cosValue; - tmi.translate[1] = 0.5 - 0.5 * sinValue - 0.5 * cosValue; - - RB_CalcTransformTexCoords( &tmi, st ); -} - - -/* -** RB_CalcSpecularAlpha -** -** Calculates specular coefficient and places it in the alpha channel -*/ -vec3_t lightOrigin = { -960, 1980, 96 }; // FIXME: track dynamically - -void RB_CalcSpecularAlpha( unsigned char *alphas ) { - int i; - float *v, *normal; - vec3_t viewer, reflected; - float l, d; - int b; - vec3_t lightDir; - int numVertexes; - - v = tess.xyz[0]; - normal = tess.normal[0]; - - alphas += 3; - - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4, alphas += 4) { - float ilength; - - VectorSubtract( lightOrigin, v, lightDir ); -// ilength = Q_rsqrt( DotProduct( lightDir, lightDir ) ); - VectorNormalizeFast( lightDir ); - - // calculate the specular color - d = DotProduct (normal, lightDir); -// d *= ilength; - - // we don't optimize for the d < 0 case since this tends to - // cause visual artifacts such as faceted "snapping" - reflected[0] = normal[0]*2*d - lightDir[0]; - reflected[1] = normal[1]*2*d - lightDir[1]; - reflected[2] = normal[2]*2*d - lightDir[2]; - - VectorSubtract (backEnd.or.viewOrigin, v, viewer); - ilength = Q_rsqrt( DotProduct( viewer, viewer ) ); - l = DotProduct (reflected, viewer); - l *= ilength; - - if (l < 0) { - b = 0; - } else { - l = l*l; - l = l*l; - b = l * 255; - if (b > 255) { - b = 255; - } - } - - *alphas = b; - } -} - -/* -** RB_CalcDiffuseColor -** -** The basic vertex lighting calc -*/ -#if idppc_altivec -static void RB_CalcDiffuseColor_altivec( unsigned char *colors ) -{ - int i; - float *v, *normal; - trRefEntity_t *ent; - int ambientLightInt; - vec3_t lightDir; - int numVertexes; - vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff); - vector float ambientLightVec; - vector float directedLightVec; - vector float lightDirVec; - vector float normalVec0, normalVec1; - vector float incomingVec0, incomingVec1, incomingVec2; - vector float zero, jVec; - vector signed int jVecInt; - vector signed short jVecShort; - vector unsigned char jVecChar, normalPerm; - ent = backEnd.currentEntity; - ambientLightInt = ent->ambientLightInt; - // A lot of this could be simplified if we made sure - // entities light info was 16-byte aligned. - jVecChar = vec_lvsl(0, ent->ambientLight); - ambientLightVec = vec_ld(0, (vector float *)ent->ambientLight); - jVec = vec_ld(11, (vector float *)ent->ambientLight); - ambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar); - - jVecChar = vec_lvsl(0, ent->directedLight); - directedLightVec = vec_ld(0,(vector float *)ent->directedLight); - jVec = vec_ld(11,(vector float *)ent->directedLight); - directedLightVec = vec_perm(directedLightVec,jVec,jVecChar); - - jVecChar = vec_lvsl(0, ent->lightDir); - lightDirVec = vec_ld(0,(vector float *)ent->lightDir); - jVec = vec_ld(11,(vector float *)ent->lightDir); - lightDirVec = vec_perm(lightDirVec,jVec,jVecChar); - - zero = (vector float)vec_splat_s8(0); - VectorCopy( ent->lightDir, lightDir ); - - v = tess.xyz[0]; - normal = tess.normal[0]; - - normalPerm = vec_lvsl(0,normal); - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { - normalVec0 = vec_ld(0,(vector float *)normal); - normalVec1 = vec_ld(11,(vector float *)normal); - normalVec0 = vec_perm(normalVec0,normalVec1,normalPerm); - incomingVec0 = vec_madd(normalVec0, lightDirVec, zero); - incomingVec1 = vec_sld(incomingVec0,incomingVec0,4); - incomingVec2 = vec_add(incomingVec0,incomingVec1); - incomingVec1 = vec_sld(incomingVec1,incomingVec1,4); - incomingVec2 = vec_add(incomingVec2,incomingVec1); - incomingVec0 = vec_splat(incomingVec2,0); - incomingVec0 = vec_max(incomingVec0,zero); - normalPerm = vec_lvsl(12,normal); - jVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec); - jVecInt = vec_cts(jVec,0); // RGBx - jVecShort = vec_pack(jVecInt,jVecInt); // RGBxRGBx - jVecChar = vec_packsu(jVecShort,jVecShort); // RGBxRGBxRGBxRGBx - jVecChar = vec_sel(jVecChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 - vec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]); // store color - } -} -#endif - -static void RB_CalcDiffuseColor_scalar( unsigned char *colors ) -{ - int i, j; - float *v, *normal; - float incoming; - trRefEntity_t *ent; - int ambientLightInt; - vec3_t ambientLight; - vec3_t lightDir; - vec3_t directedLight; - int numVertexes; - ent = backEnd.currentEntity; - ambientLightInt = ent->ambientLightInt; - VectorCopy( ent->ambientLight, ambientLight ); - VectorCopy( ent->directedLight, directedLight ); - VectorCopy( ent->lightDir, lightDir ); - - v = tess.xyz[0]; - normal = tess.normal[0]; - - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { - incoming = DotProduct (normal, lightDir); - if ( incoming <= 0 ) { - *(int *)&colors[i*4] = ambientLightInt; - continue; - } - j = ri.ftol(ambientLight[0] + incoming * directedLight[0]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+0] = j; - - j = ri.ftol(ambientLight[1] + incoming * directedLight[1]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+1] = j; - - j = ri.ftol(ambientLight[2] + incoming * directedLight[2]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+2] = j; - - colors[i*4+3] = 255; - } -} - -void RB_CalcDiffuseColor( unsigned char *colors ) -{ -#if idppc_altivec - if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. - RB_CalcDiffuseColor_altivec( colors ); - return; - } -#endif - RB_CalcDiffuseColor_scalar( colors ); -} - diff --git a/code/renderergl1/tr_shader.c b/code/renderergl1/tr_shader.c deleted file mode 100644 index 877c619123..0000000000 --- a/code/renderergl1/tr_shader.c +++ /dev/null @@ -1,3122 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -// tr_shader.c -- this file deals with the parsing and definition of shaders - -static char *s_shaderText; - -// the shader is parsed into these global variables, then copied into -// dynamically allocated memory if it is valid. -static shaderStage_t stages[MAX_SHADER_STAGES]; -static shader_t shader; -static texModInfo_t texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS]; - -#define FILE_HASH_SIZE 1024 -static shader_t* hashTable[FILE_HASH_SIZE]; - -#define MAX_SHADERTEXT_HASH 2048 -static char **shaderTextHashTable[MAX_SHADERTEXT_HASH]; - -/* -================ -return a hash value for the filename -================ -*/ -#ifdef __GNUCC__ - #warning TODO: check if long is ok here -#endif -static long generateHashValue( const char *fname, const int size ) { - int i; - long hash; - char letter; - - hash = 0; - i = 0; - while (fname[i] != '\0') { - letter = tolower(fname[i]); - if (letter =='.') break; // don't include extension - if (letter =='\\') letter = '/'; // damn path names - if (letter == PATH_SEP) letter = '/'; // damn path names - hash+=(long)(letter)*(i+119); - i++; - } - hash = (hash ^ (hash >> 10) ^ (hash >> 20)); - hash &= (size-1); - return hash; -} - -void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) { - char strippedName[MAX_QPATH]; - int hash; - shader_t *sh, *sh2; - qhandle_t h; - - sh = R_FindShaderByName( shaderName ); - if (sh == NULL || sh == tr.defaultShader) { - h = RE_RegisterShaderLightMap(shaderName, 0); - sh = R_GetShaderByHandle(h); - } - if (sh == NULL || sh == tr.defaultShader) { - ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName ); - return; - } - - sh2 = R_FindShaderByName( newShaderName ); - if (sh2 == NULL || sh2 == tr.defaultShader) { - h = RE_RegisterShaderLightMap(newShaderName, 0); - sh2 = R_GetShaderByHandle(h); - } - - if (sh2 == NULL || sh2 == tr.defaultShader) { - ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName ); - return; - } - - // remap all the shaders with the given name - // even tho they might have different lightmaps - COM_StripExtension(shaderName, strippedName, sizeof(strippedName)); - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - for (sh = hashTable[hash]; sh; sh = sh->next) { - if (Q_stricmp(sh->name, strippedName) == 0) { - if (sh != sh2) { - sh->remappedShader = sh2; - } else { - sh->remappedShader = NULL; - } - } - } - if (timeOffset) { - sh2->timeOffset = atof(timeOffset); - } -} - -/* -=============== -ParseVector -=============== -*/ -static qboolean ParseVector( char **text, int count, float *v ) { - char *token; - int i; - - // FIXME: spaces are currently required after parens, should change parseext... - token = COM_ParseExt( text, qfalse ); - if ( strcmp( token, "(" ) ) { - ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name ); - return qfalse; - } - - for ( i = 0 ; i < count ; i++ ) { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) { - ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name ); - return qfalse; - } - v[i] = atof( token ); - } - - token = COM_ParseExt( text, qfalse ); - if ( strcmp( token, ")" ) ) { - ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name ); - return qfalse; - } - - return qtrue; -} - - -/* -=============== -NameToAFunc -=============== -*/ -static unsigned NameToAFunc( const char *funcname ) -{ - if ( !Q_stricmp( funcname, "GT0" ) ) - { - return GLS_ATEST_GT_0; - } - else if ( !Q_stricmp( funcname, "LT128" ) ) - { - return GLS_ATEST_LT_80; - } - else if ( !Q_stricmp( funcname, "GE128" ) ) - { - return GLS_ATEST_GE_80; - } - - ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name ); - return 0; -} - - -/* -=============== -NameToSrcBlendMode -=============== -*/ -static int NameToSrcBlendMode( const char *name ) -{ - if ( !Q_stricmp( name, "GL_ONE" ) ) - { - return GLS_SRCBLEND_ONE; - } - else if ( !Q_stricmp( name, "GL_ZERO" ) ) - { - return GLS_SRCBLEND_ZERO; - } - else if ( !Q_stricmp( name, "GL_DST_COLOR" ) ) - { - return GLS_SRCBLEND_DST_COLOR; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) ) - { - return GLS_SRCBLEND_ONE_MINUS_DST_COLOR; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) - { - return GLS_SRCBLEND_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) - { - return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) - { - return GLS_SRCBLEND_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) - { - return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) ) - { - return GLS_SRCBLEND_ALPHA_SATURATE; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name ); - return GLS_SRCBLEND_ONE; -} - -/* -=============== -NameToDstBlendMode -=============== -*/ -static int NameToDstBlendMode( const char *name ) -{ - if ( !Q_stricmp( name, "GL_ONE" ) ) - { - return GLS_DSTBLEND_ONE; - } - else if ( !Q_stricmp( name, "GL_ZERO" ) ) - { - return GLS_DSTBLEND_ZERO; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) - { - return GLS_DSTBLEND_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) - { - return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) - { - return GLS_DSTBLEND_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) - { - return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) ) - { - return GLS_DSTBLEND_SRC_COLOR; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) ) - { - return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name ); - return GLS_DSTBLEND_ONE; -} - -/* -=============== -NameToGenFunc -=============== -*/ -static genFunc_t NameToGenFunc( const char *funcname ) -{ - if ( !Q_stricmp( funcname, "sin" ) ) - { - return GF_SIN; - } - else if ( !Q_stricmp( funcname, "square" ) ) - { - return GF_SQUARE; - } - else if ( !Q_stricmp( funcname, "triangle" ) ) - { - return GF_TRIANGLE; - } - else if ( !Q_stricmp( funcname, "sawtooth" ) ) - { - return GF_SAWTOOTH; - } - else if ( !Q_stricmp( funcname, "inversesawtooth" ) ) - { - return GF_INVERSE_SAWTOOTH; - } - else if ( !Q_stricmp( funcname, "noise" ) ) - { - return GF_NOISE; - } - - ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name ); - return GF_SIN; -} - - -/* -=================== -ParseWaveForm -=================== -*/ -static void ParseWaveForm( char **text, waveForm_t *wave ) -{ - char *token; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->func = NameToGenFunc( token ); - - // BASE, AMP, PHASE, FREQ - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->base = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->phase = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->frequency = atof( token ); -} - - -/* -=================== -ParseTexMod -=================== -*/ -static void ParseTexMod( char *_text, shaderStage_t *stage ) -{ - const char *token; - char **text = &_text; - texModInfo_t *tmi; - - if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) { - ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'", shader.name ); - return; - } - - tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods]; - stage->bundle[0].numTexMods++; - - token = COM_ParseExt( text, qfalse ); - - // - // turb - // - if ( !Q_stricmp( token, "turb" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.base = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.amplitude = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.phase = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.frequency = atof( token ); - - tmi->type = TMOD_TURBULENT; - } - // - // scale - // - else if ( !Q_stricmp( token, "scale" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name ); - return; - } - tmi->scale[0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name ); - return; - } - tmi->scale[1] = atof( token ); - tmi->type = TMOD_SCALE; - } - // - // scroll - // - else if ( !Q_stricmp( token, "scroll" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); - return; - } - tmi->scroll[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); - return; - } - tmi->scroll[1] = atof( token ); - tmi->type = TMOD_SCROLL; - } - // - // stretch - // - else if ( !Q_stricmp( token, "stretch" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.func = NameToGenFunc( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.base = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.phase = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.frequency = atof( token ); - - tmi->type = TMOD_STRETCH; - } - // - // transform - // - else if ( !Q_stricmp( token, "transform" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[0][0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[0][1] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[1][0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[1][1] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->translate[0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->translate[1] = atof( token ); - - tmi->type = TMOD_TRANSFORM; - } - // - // rotate - // - else if ( !Q_stricmp( token, "rotate" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name ); - return; - } - tmi->rotateSpeed = atof( token ); - tmi->type = TMOD_ROTATE; - } - // - // entityTranslate - // - else if ( !Q_stricmp( token, "entityTranslate" ) ) - { - tmi->type = TMOD_ENTITY_TRANSLATE; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name ); - } -} - - -/* -=================== -ParseStage -=================== -*/ -static qboolean ParseStage( shaderStage_t *stage, char **text ) -{ - char *token; - int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0; - qboolean depthMaskExplicit = qfalse; - - stage->active = qtrue; - - while ( 1 ) - { - token = COM_ParseExt( text, qtrue ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" ); - return qfalse; - } - - if ( token[0] == '}' ) - { - break; - } - // - // map - // - else if ( !Q_stricmp( token, "map" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if ( !Q_stricmp( token, "$whiteimage" ) ) - { - stage->bundle[0].image[0] = tr.whiteImage; - continue; - } - else if ( !Q_stricmp( token, "$lightmap" ) ) - { - stage->bundle[0].isLightmap = qtrue; - if ( shader.lightmapIndex < 0 || !tr.lightmaps ) { - stage->bundle[0].image[0] = tr.whiteImage; - } else { - stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - } - continue; - } - else - { - imgType_t type = IMGTYPE_COLORALPHA; - imgFlags_t flags = IMGFLAG_NONE; - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); - - if ( !stage->bundle[0].image[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - } - // - // clampmap - // - else if ( !Q_stricmp( token, "clampmap" ) ) - { - imgType_t type = IMGTYPE_COLORALPHA; - imgFlags_t flags = IMGFLAG_CLAMPTOEDGE; - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); - if ( !stage->bundle[0].image[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - // - // animMap .... - // - else if ( !Q_stricmp( token, "animMap" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[0].imageAnimationSpeed = atof( token ); - - // parse up to MAX_IMAGE_ANIMATIONS animations - while ( 1 ) { - int num; - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) { - break; - } - num = stage->bundle[0].numImageAnimations; - if ( num < MAX_IMAGE_ANIMATIONS ) { - imgFlags_t flags = IMGFLAG_NONE; - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); - if ( !stage->bundle[0].image[num] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - stage->bundle[0].numImageAnimations++; - } - } - } - else if ( !Q_stricmp( token, "videoMap" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); - if (stage->bundle[0].videoMapHandle != -1) { - stage->bundle[0].isVideoMap = qtrue; - stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle]; - } - } - // - // alphafunc - // - else if ( !Q_stricmp( token, "alphaFunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - atestBits = NameToAFunc( token ); - } - // - // depthFunc - // - else if ( !Q_stricmp( token, "depthfunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if ( !Q_stricmp( token, "lequal" ) ) - { - depthFuncBits = 0; - } - else if ( !Q_stricmp( token, "equal" ) ) - { - depthFuncBits = GLS_DEPTHFUNC_EQUAL; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // detail - // - else if ( !Q_stricmp( token, "detail" ) ) - { - stage->isDetail = qtrue; - } - // - // blendfunc - // or blendfunc - // - else if ( !Q_stricmp( token, "blendfunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); - continue; - } - // check for "simple" blends first - if ( !Q_stricmp( token, "add" ) ) { - blendSrcBits = GLS_SRCBLEND_ONE; - blendDstBits = GLS_DSTBLEND_ONE; - } else if ( !Q_stricmp( token, "filter" ) ) { - blendSrcBits = GLS_SRCBLEND_DST_COLOR; - blendDstBits = GLS_DSTBLEND_ZERO; - } else if ( !Q_stricmp( token, "blend" ) ) { - blendSrcBits = GLS_SRCBLEND_SRC_ALPHA; - blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else { - // complex double blends - blendSrcBits = NameToSrcBlendMode( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); - continue; - } - blendDstBits = NameToDstBlendMode( token ); - } - - // clear depth mask for blended surfaces - if ( !depthMaskExplicit ) - { - depthMaskBits = 0; - } - } - // - // rgbGen - // - else if ( !Q_stricmp( token, "rgbGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - ParseWaveForm( text, &stage->rgbWave ); - stage->rgbGen = CGEN_WAVEFORM; - } - else if ( !Q_stricmp( token, "const" ) ) - { - vec3_t color; - - ParseVector( text, 3, color ); - stage->constantColor[0] = 255 * color[0]; - stage->constantColor[1] = 255 * color[1]; - stage->constantColor[2] = 255 * color[2]; - - stage->rgbGen = CGEN_CONST; - } - else if ( !Q_stricmp( token, "identity" ) ) - { - stage->rgbGen = CGEN_IDENTITY; - } - else if ( !Q_stricmp( token, "identityLighting" ) ) - { - stage->rgbGen = CGEN_IDENTITY_LIGHTING; - } - else if ( !Q_stricmp( token, "entity" ) ) - { - stage->rgbGen = CGEN_ENTITY; - } - else if ( !Q_stricmp( token, "oneMinusEntity" ) ) - { - stage->rgbGen = CGEN_ONE_MINUS_ENTITY; - } - else if ( !Q_stricmp( token, "vertex" ) ) - { - stage->rgbGen = CGEN_VERTEX; - if ( stage->alphaGen == 0 ) { - stage->alphaGen = AGEN_VERTEX; - } - } - else if ( !Q_stricmp( token, "exactVertex" ) ) - { - stage->rgbGen = CGEN_EXACT_VERTEX; - } - else if ( !Q_stricmp( token, "lightingDiffuse" ) ) - { - stage->rgbGen = CGEN_LIGHTING_DIFFUSE; - } - else if ( !Q_stricmp( token, "oneMinusVertex" ) ) - { - stage->rgbGen = CGEN_ONE_MINUS_VERTEX; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // alphaGen - // - else if ( !Q_stricmp( token, "alphaGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - ParseWaveForm( text, &stage->alphaWave ); - stage->alphaGen = AGEN_WAVEFORM; - } - else if ( !Q_stricmp( token, "const" ) ) - { - token = COM_ParseExt( text, qfalse ); - stage->constantColor[3] = 255 * atof( token ); - stage->alphaGen = AGEN_CONST; - } - else if ( !Q_stricmp( token, "identity" ) ) - { - stage->alphaGen = AGEN_IDENTITY; - } - else if ( !Q_stricmp( token, "entity" ) ) - { - stage->alphaGen = AGEN_ENTITY; - } - else if ( !Q_stricmp( token, "oneMinusEntity" ) ) - { - stage->alphaGen = AGEN_ONE_MINUS_ENTITY; - } - else if ( !Q_stricmp( token, "vertex" ) ) - { - stage->alphaGen = AGEN_VERTEX; - } - else if ( !Q_stricmp( token, "lightingSpecular" ) ) - { - stage->alphaGen = AGEN_LIGHTING_SPECULAR; - } - else if ( !Q_stricmp( token, "oneMinusVertex" ) ) - { - stage->alphaGen = AGEN_ONE_MINUS_VERTEX; - } - else if ( !Q_stricmp( token, "portal" ) ) - { - stage->alphaGen = AGEN_PORTAL; - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - shader.portalRange = 256; - ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name ); - } - else - { - shader.portalRange = atof( token ); - } - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // tcGen - // - else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "environment" ) ) - { - stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED; - } - else if ( !Q_stricmp( token, "lightmap" ) ) - { - stage->bundle[0].tcGen = TCGEN_LIGHTMAP; - } - else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) ) - { - stage->bundle[0].tcGen = TCGEN_TEXTURE; - } - else if ( !Q_stricmp( token, "vector" ) ) - { - ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] ); - ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] ); - - stage->bundle[0].tcGen = TCGEN_VECTOR; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name ); - } - } - // - // tcMod <...> - // - else if ( !Q_stricmp( token, "tcMod" ) ) - { - char buffer[1024] = ""; - - while ( 1 ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - break; - strcat( buffer, token ); - strcat( buffer, " " ); - } - - ParseTexMod( buffer, stage ); - - continue; - } - // - // depthmask - // - else if ( !Q_stricmp( token, "depthwrite" ) ) - { - depthMaskBits = GLS_DEPTHMASK_TRUE; - depthMaskExplicit = qtrue; - - continue; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - - // - // if cgen isn't explicitly specified, use either identity or identitylighting - // - if ( stage->rgbGen == CGEN_BAD ) { - if ( blendSrcBits == 0 || - blendSrcBits == GLS_SRCBLEND_ONE || - blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) { - stage->rgbGen = CGEN_IDENTITY_LIGHTING; - } else { - stage->rgbGen = CGEN_IDENTITY; - } - } - - - // - // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending - // - if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && - ( blendDstBits == GLS_DSTBLEND_ZERO ) ) - { - blendDstBits = blendSrcBits = 0; - depthMaskBits = GLS_DEPTHMASK_TRUE; - } - - // decide which agens we can skip - if ( stage->alphaGen == AGEN_IDENTITY ) { - if ( stage->rgbGen == CGEN_IDENTITY - || stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) { - stage->alphaGen = AGEN_SKIP; - } - } - - // - // compute state bits - // - stage->stateBits = depthMaskBits | - blendSrcBits | blendDstBits | - atestBits | - depthFuncBits; - - return qtrue; -} - -/* -=============== -ParseDeform - -deformVertexes wave -deformVertexes normal -deformVertexes move -deformVertexes bulge -deformVertexes projectionShadow -deformVertexes autoSprite -deformVertexes autoSprite2 -deformVertexes text[0-7] -=============== -*/ -static void ParseDeform( char **text ) { - char *token; - deformStage_t *ds; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name ); - return; - } - - if ( shader.numDeforms == MAX_SHADER_DEFORMS ) { - ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name ); - return; - } - - ds = &shader.deforms[ shader.numDeforms ]; - shader.numDeforms++; - - if ( !Q_stricmp( token, "projectionShadow" ) ) { - ds->deformation = DEFORM_PROJECTION_SHADOW; - return; - } - - if ( !Q_stricmp( token, "autosprite" ) ) { - ds->deformation = DEFORM_AUTOSPRITE; - return; - } - - if ( !Q_stricmp( token, "autosprite2" ) ) { - ds->deformation = DEFORM_AUTOSPRITE2; - return; - } - - if ( !Q_stricmpn( token, "text", 4 ) ) { - int n; - - n = token[4] - '0'; - if ( n < 0 || n > 7 ) { - n = 0; - } - ds->deformation = DEFORM_TEXT0 + n; - return; - } - - if ( !Q_stricmp( token, "bulge" ) ) { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeWidth = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeHeight = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeSpeed = atof( token ); - - ds->deformation = DEFORM_BULGE; - return; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - - if ( atof( token ) != 0 ) - { - ds->deformationSpread = 1.0f / atof( token ); - } - else - { - ds->deformationSpread = 100.0f; - ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name ); - } - - ParseWaveForm( text, &ds->deformationWave ); - ds->deformation = DEFORM_WAVE; - return; - } - - if ( !Q_stricmp( token, "normal" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->deformationWave.amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->deformationWave.frequency = atof( token ); - - ds->deformation = DEFORM_NORMALS; - return; - } - - if ( !Q_stricmp( token, "move" ) ) { - int i; - - for ( i = 0 ; i < 3 ; i++ ) { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->moveVector[i] = atof( token ); - } - - ParseWaveForm( text, &ds->deformationWave ); - ds->deformation = DEFORM_MOVE; - return; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name ); -} - - -/* -=============== -ParseSkyParms - -skyParms -=============== -*/ -static void ParseSkyParms( char **text ) { - char *token; - static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; - char pathname[MAX_QPATH]; - int i; - imgFlags_t imgFlags = IMGFLAG_MIPMAP | IMGFLAG_PICMIP; - - // outerbox - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - if ( strcmp( token, "-" ) ) { - for (i=0 ; i<6 ; i++) { - Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" - , token, suf[i] ); - shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags | IMGFLAG_CLAMPTOEDGE ); - - if ( !shader.sky.outerbox[i] ) { - shader.sky.outerbox[i] = tr.defaultImage; - } - } - } - - // cloudheight - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - shader.sky.cloudHeight = atof( token ); - if ( !shader.sky.cloudHeight ) { - shader.sky.cloudHeight = 512; - } - R_InitSkyTexCoords( shader.sky.cloudHeight ); - - - // innerbox - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - if ( strcmp( token, "-" ) ) { - for (i=0 ; i<6 ; i++) { - Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" - , token, suf[i] ); - shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags ); - if ( !shader.sky.innerbox[i] ) { - shader.sky.innerbox[i] = tr.defaultImage; - } - } - } - - shader.isSky = qtrue; -} - - -/* -================= -ParseSort -================= -*/ -void ParseSort( char **text ) { - char *token; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name ); - return; - } - - if ( !Q_stricmp( token, "portal" ) ) { - shader.sort = SS_PORTAL; - } else if ( !Q_stricmp( token, "sky" ) ) { - shader.sort = SS_ENVIRONMENT; - } else if ( !Q_stricmp( token, "opaque" ) ) { - shader.sort = SS_OPAQUE; - }else if ( !Q_stricmp( token, "decal" ) ) { - shader.sort = SS_DECAL; - } else if ( !Q_stricmp( token, "seeThrough" ) ) { - shader.sort = SS_SEE_THROUGH; - } else if ( !Q_stricmp( token, "banner" ) ) { - shader.sort = SS_BANNER; - } else if ( !Q_stricmp( token, "additive" ) ) { - shader.sort = SS_BLEND1; - } else if ( !Q_stricmp( token, "nearest" ) ) { - shader.sort = SS_NEAREST; - } else if ( !Q_stricmp( token, "underwater" ) ) { - shader.sort = SS_UNDERWATER; - } else { - shader.sort = atof( token ); - } -} - - - -// this table is also present in q3map - -typedef struct { - char *name; - int clearSolid, surfaceFlags, contents; -} infoParm_t; - -infoParm_t infoParms[] = { - // server relevant contents - {"water", 1, 0, CONTENTS_WATER }, - {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging - {"lava", 1, 0, CONTENTS_LAVA }, // very damaging - {"playerclip", 1, 0, CONTENTS_PLAYERCLIP }, - {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP }, - {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc) - {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag - - // utility relevant attributes - {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes - {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces - {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp - {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas - {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas - {"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots - {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots - - {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering - {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map - {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it - {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis - {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter - - // server attributes - {"slick", 0, SURF_SLICK, 0 }, - {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks - {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode - {"ladder", 0, SURF_LADDER, 0 }, - {"nodamage", 0, SURF_NODAMAGE, 0 }, - {"metalsteps", 0, SURF_METALSTEPS,0 }, - {"flesh", 0, SURF_FLESH, 0 }, - {"nosteps", 0, SURF_NOSTEPS, 0 }, - - // drawsurf attributes - {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap) - {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes - {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap - {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights - {"dust", 0, SURF_DUST, 0} // leave a dust trail when walking on this surface -}; - - -/* -=============== -ParseSurfaceParm - -surfaceparm -=============== -*/ -static void ParseSurfaceParm( char **text ) { - char *token; - int numInfoParms = ARRAY_LEN( infoParms ); - int i; - - token = COM_ParseExt( text, qfalse ); - for ( i = 0 ; i < numInfoParms ; i++ ) { - if ( !Q_stricmp( token, infoParms[i].name ) ) { - shader.surfaceFlags |= infoParms[i].surfaceFlags; - shader.contentFlags |= infoParms[i].contents; -#if 0 - if ( infoParms[i].clearSolid ) { - si->contents &= ~CONTENTS_SOLID; - } -#endif - break; - } - } -} - -/* -================= -ParseShader - -The current text pointer is at the explicit text definition of the -shader. Parse it into the global shader variable. Later functions -will optimize it. -================= -*/ -static qboolean ParseShader( char **text ) -{ - char *token; - int s; - - s = 0; - - token = COM_ParseExt( text, qtrue ); - if ( token[0] != '{' ) - { - ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name ); - return qfalse; - } - - while ( 1 ) - { - token = COM_ParseExt( text, qtrue ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name ); - return qfalse; - } - - // end of shader definition - if ( token[0] == '}' ) - { - break; - } - // stage definition - else if ( token[0] == '{' ) - { - if ( s >= MAX_SHADER_STAGES ) { - ri.Printf( PRINT_WARNING, "WARNING: too many stages in shader %s\n", shader.name ); - return qfalse; - } - - if ( !ParseStage( &stages[s], text ) ) - { - return qfalse; - } - stages[s].active = qtrue; - s++; - - continue; - } - // skip stuff that only the QuakeEdRadient needs - else if ( !Q_stricmpn( token, "qer", 3 ) ) { - SkipRestOfLine( text ); - continue; - } - // sun parms - else if ( !Q_stricmp( token, "q3map_sun" ) ) { - float a, b; - - token = COM_ParseExt( text, qfalse ); - tr.sunLight[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.sunLight[1] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.sunLight[2] = atof( token ); - - VectorNormalize( tr.sunLight ); - - token = COM_ParseExt( text, qfalse ); - a = atof( token ); - VectorScale( tr.sunLight, a, tr.sunLight); - - token = COM_ParseExt( text, qfalse ); - a = atof( token ); - a = a / 180 * M_PI; - - token = COM_ParseExt( text, qfalse ); - b = atof( token ); - b = b / 180 * M_PI; - - tr.sunDirection[0] = cos( a ) * cos( b ); - tr.sunDirection[1] = sin( a ) * cos( b ); - tr.sunDirection[2] = sin( b ); - } - else if ( !Q_stricmp( token, "deformVertexes" ) ) { - ParseDeform( text ); - continue; - } - else if ( !Q_stricmp( token, "tesssize" ) ) { - SkipRestOfLine( text ); - continue; - } - else if ( !Q_stricmp( token, "clampTime" ) ) { - token = COM_ParseExt( text, qfalse ); - if (token[0]) { - shader.clampTime = atof(token); - } - } - // skip stuff that only the q3map needs - else if ( !Q_stricmpn( token, "q3map", 5 ) ) { - SkipRestOfLine( text ); - continue; - } - // skip stuff that only q3map or the server needs - else if ( !Q_stricmp( token, "surfaceParm" ) ) { - ParseSurfaceParm( text ); - continue; - } - // no mip maps - else if ( !Q_stricmp( token, "nomipmaps" ) ) - { - shader.noMipMaps = qtrue; - shader.noPicMip = qtrue; - continue; - } - // no picmip adjustment - else if ( !Q_stricmp( token, "nopicmip" ) ) - { - shader.noPicMip = qtrue; - continue; - } - // polygonOffset - else if ( !Q_stricmp( token, "polygonOffset" ) ) - { - shader.polygonOffset = qtrue; - continue; - } - // entityMergable, allowing sprite surfaces from multiple entities - // to be merged into one batch. This is a savings for smoke - // puffs and blood, but can't be used for anything where the - // shader calcs (not the surface function) reference the entity color or scroll - else if ( !Q_stricmp( token, "entityMergable" ) ) - { - shader.entityMergable = qtrue; - continue; - } - // fogParms - else if ( !Q_stricmp( token, "fogParms" ) ) - { - if ( !ParseVector( text, 3, shader.fogParms.color ) ) { - return qfalse; - } - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name ); - continue; - } - shader.fogParms.depthForOpaque = atof( token ); - - // skip any old gradient directions - SkipRestOfLine( text ); - continue; - } - // portal - else if ( !Q_stricmp(token, "portal") ) - { - shader.sort = SS_PORTAL; - continue; - } - // skyparms - else if ( !Q_stricmp( token, "skyparms" ) ) - { - ParseSkyParms( text ); - continue; - } - // light determines flaring in q3map, not needed here - else if ( !Q_stricmp(token, "light") ) - { - (void)COM_ParseExt( text, qfalse ); - continue; - } - // cull - else if ( !Q_stricmp( token, "cull") ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) ) - { - shader.cullType = CT_TWO_SIDED; - } - else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) ) - { - shader.cullType = CT_BACK_SIDED; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name ); - } - continue; - } - // sort - else if ( !Q_stricmp( token, "sort" ) ) - { - ParseSort( text ); - continue; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name ); - return qfalse; - } - } - - // - // ignore shaders that don't have any stages, unless it is a sky or fog - // - if ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) { - return qfalse; - } - - shader.explicitlyDefined = qtrue; - - return qtrue; -} - -/* -======================================================================================== - -SHADER OPTIMIZATION AND FOGGING - -======================================================================================== -*/ - -/* -=================== -ComputeStageIteratorFunc - -See if we can use on of the simple fastpath stage functions, -otherwise set to the generic stage function -=================== -*/ -static void ComputeStageIteratorFunc( void ) -{ - shader.optimalStageIteratorFunc = RB_StageIteratorGeneric; - - // - // see if this should go into the sky path - // - if ( shader.isSky ) - { - shader.optimalStageIteratorFunc = RB_StageIteratorSky; - return; - } - - if ( r_ignoreFastPath->integer ) - { - return; - } - - // - // see if this can go into the vertex lit fast path - // - if ( shader.numUnfoggedPasses == 1 ) - { - if ( stages[0].rgbGen == CGEN_LIGHTING_DIFFUSE ) - { - if ( stages[0].alphaGen == AGEN_IDENTITY ) - { - if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE ) - { - if ( !shader.polygonOffset ) - { - if ( !shader.multitextureEnv ) - { - if ( !shader.numDeforms ) - { - shader.optimalStageIteratorFunc = RB_StageIteratorVertexLitTexture; - return; - } - } - } - } - } - } - } - - // - // see if this can go into an optimized LM, multitextured path - // - if ( shader.numUnfoggedPasses == 1 ) - { - if ( ( stages[0].rgbGen == CGEN_IDENTITY ) && ( stages[0].alphaGen == AGEN_IDENTITY ) ) - { - if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE && - stages[0].bundle[1].tcGen == TCGEN_LIGHTMAP ) - { - if ( !shader.polygonOffset ) - { - if ( !shader.numDeforms ) - { - if ( shader.multitextureEnv ) - { - shader.optimalStageIteratorFunc = RB_StageIteratorLightmappedMultitexture; - } - } - } - } - } - } -} - -typedef struct { - int blendA; - int blendB; - - int multitextureEnv; - int multitextureBlend; -} collapse_t; - -static collapse_t collapse[] = { - { 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, 0 }, - - { 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, 0 }, - - { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, - GL_ADD, 0 }, - - { GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, - GL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE }, -#if 0 - { 0, GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA, - GL_DECAL, 0 }, -#endif - { -1 } -}; - -/* -================ -CollapseMultitexture - -Attempt to combine two stages into a single multitexture stage -FIXME: I think modulated add + modulated add collapses incorrectly -================= -*/ -static qboolean CollapseMultitexture( void ) { - int abits, bbits; - int i; - textureBundle_t tmpBundle; - - if ( !qglActiveTextureARB ) { - return qfalse; - } - - // make sure both stages are active - if ( !stages[0].active || !stages[1].active ) { - return qfalse; - } - - // on voodoo2, don't combine different tmus - if ( glConfig.driverType == GLDRV_VOODOO ) { - if ( stages[0].bundle[0].image[0]->TMU == - stages[1].bundle[0].image[0]->TMU ) { - return qfalse; - } - } - - abits = stages[0].stateBits; - bbits = stages[1].stateBits; - - // make sure that both stages have identical state other than blend modes - if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) != - ( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) { - return qfalse; - } - - abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - - // search for a valid multitexture blend function - for ( i = 0; collapse[i].blendA != -1 ; i++ ) { - if ( abits == collapse[i].blendA - && bbits == collapse[i].blendB ) { - break; - } - } - - // nothing found - if ( collapse[i].blendA == -1 ) { - return qfalse; - } - - // GL_ADD is a separate extension - if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) { - return qfalse; - } - - // make sure waveforms have identical parameters - if ( ( stages[0].rgbGen != stages[1].rgbGen ) || - ( stages[0].alphaGen != stages[1].alphaGen ) ) { - return qfalse; - } - - // an add collapse can only have identity colors - if ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) { - return qfalse; - } - - if ( stages[0].rgbGen == CGEN_WAVEFORM ) - { - if ( memcmp( &stages[0].rgbWave, - &stages[1].rgbWave, - sizeof( stages[0].rgbWave ) ) ) - { - return qfalse; - } - } - if ( stages[0].alphaGen == AGEN_WAVEFORM ) - { - if ( memcmp( &stages[0].alphaWave, - &stages[1].alphaWave, - sizeof( stages[0].alphaWave ) ) ) - { - return qfalse; - } - } - - - // make sure that lightmaps are in bundle 1 for 3dfx - if ( stages[0].bundle[0].isLightmap ) - { - tmpBundle = stages[0].bundle[0]; - stages[0].bundle[0] = stages[1].bundle[0]; - stages[0].bundle[1] = tmpBundle; - } - else - { - stages[0].bundle[1] = stages[1].bundle[0]; - } - - // set the new blend state bits - shader.multitextureEnv = collapse[i].multitextureEnv; - stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - stages[0].stateBits |= collapse[i].multitextureBlend; - - // - // move down subsequent shaders - // - memmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) ); - Com_Memset( &stages[MAX_SHADER_STAGES-1], 0, sizeof( stages[0] ) ); - - return qtrue; -} - -/* -============= - -FixRenderCommandList -https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493 -Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated -but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces -to be rendered with bad shaders. To fix this, need to go through all render commands and fix -sortedIndex. -============== -*/ -static void FixRenderCommandList( int newShader ) { - renderCommandList_t *cmdList = &backEndData->commands; - - if( cmdList ) { - const void *curCmd = cmdList->cmds; - - while ( 1 ) { - curCmd = PADP(curCmd, sizeof(void *)); - - switch ( *(const int *)curCmd ) { - case RC_SET_COLOR: - { - const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd; - curCmd = (const void *)(sc_cmd + 1); - break; - } - case RC_STRETCH_PIC: - { - const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd; - curCmd = (const void *)(sp_cmd + 1); - break; - } - case RC_DRAW_SURFS: - { - int i; - drawSurf_t *drawSurf; - shader_t *shader; - int fogNum; - int entityNum; - int dlightMap; - int sortedIndex; - const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd; - - for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) { - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap ); - sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1)); - if( sortedIndex >= newShader ) { - sortedIndex++; - drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap; - } - } - curCmd = (const void *)(ds_cmd + 1); - break; - } - case RC_DRAW_BUFFER: - { - const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd; - curCmd = (const void *)(db_cmd + 1); - break; - } - case RC_SWAP_BUFFERS: - { - const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd; - curCmd = (const void *)(sb_cmd + 1); - break; - } - case RC_END_OF_LIST: - default: - return; - } - } - } -} - -/* -============== -SortNewShader - -Positions the most recently created shader in the tr.sortedShaders[] -array so that the shader->sort key is sorted relative to the other -shaders. - -Sets shader->sortedIndex -============== -*/ -static void SortNewShader( void ) { - int i; - float sort; - shader_t *newShader; - - newShader = tr.shaders[ tr.numShaders - 1 ]; - sort = newShader->sort; - - for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) { - if ( tr.sortedShaders[ i ]->sort <= sort ) { - break; - } - tr.sortedShaders[i+1] = tr.sortedShaders[i]; - tr.sortedShaders[i+1]->sortedIndex++; - } - - // Arnout: fix rendercommandlist - // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493 - FixRenderCommandList( i+1 ); - - newShader->sortedIndex = i+1; - tr.sortedShaders[i+1] = newShader; -} - - -/* -==================== -GeneratePermanentShader -==================== -*/ -static shader_t *GeneratePermanentShader( void ) { - shader_t *newShader; - int i, b; - int size, hash; - - if ( tr.numShaders == MAX_SHADERS ) { - ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n"); - return tr.defaultShader; - } - - newShader = ri.Hunk_Alloc( sizeof( shader_t ), h_low ); - - *newShader = shader; - - if ( shader.sort <= SS_OPAQUE ) { - newShader->fogPass = FP_EQUAL; - } else if ( shader.contentFlags & CONTENTS_FOG ) { - newShader->fogPass = FP_LE; - } - - tr.shaders[ tr.numShaders ] = newShader; - newShader->index = tr.numShaders; - - tr.sortedShaders[ tr.numShaders ] = newShader; - newShader->sortedIndex = tr.numShaders; - - tr.numShaders++; - - for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) { - if ( !stages[i].active ) { - break; - } - newShader->stages[i] = ri.Hunk_Alloc( sizeof( stages[i] ), h_low ); - *newShader->stages[i] = stages[i]; - - for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) { - size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t ); - newShader->stages[i]->bundle[b].texMods = ri.Hunk_Alloc( size, h_low ); - Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size ); - } - } - - SortNewShader(); - - hash = generateHashValue(newShader->name, FILE_HASH_SIZE); - newShader->next = hashTable[hash]; - hashTable[hash] = newShader; - - return newShader; -} - -/* -================= -VertexLightingCollapse - -If vertex lighting is enabled, only render a single -pass, trying to guess which is the correct one to best aproximate -what it is supposed to look like. -================= -*/ -static void VertexLightingCollapse( void ) { - int stage; - shaderStage_t *bestStage; - int bestImageRank; - int rank; - - // if we aren't opaque, just use the first pass - if ( shader.sort == SS_OPAQUE ) { - - // pick the best texture for the single pass - bestStage = &stages[0]; - bestImageRank = -999999; - - for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - rank = 0; - - if ( pStage->bundle[0].isLightmap ) { - rank -= 100; - } - if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) { - rank -= 5; - } - if ( pStage->bundle[0].numTexMods ) { - rank -= 5; - } - if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) { - rank -= 3; - } - - if ( rank > bestImageRank ) { - bestImageRank = rank; - bestStage = pStage; - } - } - - stages[0].bundle[0] = bestStage->bundle[0]; - stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - stages[0].stateBits |= GLS_DEPTHMASK_TRUE; - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - } else { - stages[0].rgbGen = CGEN_EXACT_VERTEX; - } - stages[0].alphaGen = AGEN_SKIP; - } else { - // don't use a lightmap (tesla coils) - if ( stages[0].bundle[0].isLightmap ) { - stages[0] = stages[1]; - } - - // if we were in a cross-fade cgen, hack it to normal - if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH ) - && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH ) - && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - } - - for ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - - Com_Memset( pStage, 0, sizeof( *pStage ) ); - } -} - -/* -========================= -FinishShader - -Returns a freshly allocated shader with all the needed info -from the current global working shader -========================= -*/ -static shader_t *FinishShader( void ) { - int stage; - qboolean hasLightmapStage; - qboolean vertexLightmap; - - hasLightmapStage = qfalse; - vertexLightmap = qfalse; - - // - // set sky stuff appropriate - // - if ( shader.isSky ) { - shader.sort = SS_ENVIRONMENT; - } - - // - // set polygon offset - // - if ( shader.polygonOffset && !shader.sort ) { - shader.sort = SS_DECAL; - } - - // - // set appropriate stage information - // - for ( stage = 0; stage < MAX_SHADER_STAGES; ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - - // check for a missing texture - if ( !pStage->bundle[0].image[0] ) { - ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name ); - pStage->active = qfalse; - stage++; - continue; - } - - // - // ditch this stage if it's detail and detail textures are disabled - // - if ( pStage->isDetail && !r_detailTextures->integer ) - { - int index; - - for(index = stage + 1; index < MAX_SHADER_STAGES; index++) - { - if(!stages[index].active) - break; - } - - if(index < MAX_SHADER_STAGES) - memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage)); - else - { - if(stage + 1 < MAX_SHADER_STAGES) - memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage - 1)); - - Com_Memset(&stages[index - 1], 0, sizeof(*stages)); - } - - continue; - } - - // - // default texture coordinate generation - // - if ( pStage->bundle[0].isLightmap ) { - if ( pStage->bundle[0].tcGen == TCGEN_BAD ) { - pStage->bundle[0].tcGen = TCGEN_LIGHTMAP; - } - hasLightmapStage = qtrue; - } else { - if ( pStage->bundle[0].tcGen == TCGEN_BAD ) { - pStage->bundle[0].tcGen = TCGEN_TEXTURE; - } - } - - - // not a true lightmap but we want to leave existing - // behaviour in place and not print out a warning - //if (pStage->rgbGen == CGEN_VERTEX) { - // vertexLightmap = qtrue; - //} - - - - // - // determine sort order and fog color adjustment - // - if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) && - ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) { - int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS; - int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS; - - // fog color adjustment only works for blend modes that have a contribution - // that aproaches 0 as the modulate values aproach 0 -- - // GL_ONE, GL_ONE - // GL_ZERO, GL_ONE_MINUS_SRC_COLOR - // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA - - // modulate, additive - if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) || - ( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) { - pStage->adjustColorsForFog = ACFF_MODULATE_RGB; - } - // strict blend - else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) - { - pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA; - } - // premultiplied alpha - else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) - { - pStage->adjustColorsForFog = ACFF_MODULATE_RGBA; - } else { - // we can't adjust this one correctly, so it won't be exactly correct in fog - } - - // don't screw with sort order if this is a portal or environment - if ( !shader.sort ) { - // see through item, like a grill or grate - if ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) { - shader.sort = SS_SEE_THROUGH; - } else { - shader.sort = SS_BLEND0; - } - } - } - - stage++; - } - - // there are times when you will need to manually apply a sort to - // opaque alpha tested shaders that have later blend passes - if ( !shader.sort ) { - shader.sort = SS_OPAQUE; - } - - // - // if we are in r_vertexLight mode, never use a lightmap texture - // - if ( stage > 1 && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) { - VertexLightingCollapse(); - stage = 1; - hasLightmapStage = qfalse; - } - - // - // look for multitexture potential - // - if ( stage > 1 && CollapseMultitexture() ) { - stage--; - } - - if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) { - if (vertexLightmap) { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name ); - } else { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name ); - shader.lightmapIndex = LIGHTMAP_NONE; - } - } - - - // - // compute number of passes - // - shader.numUnfoggedPasses = stage; - - // fogonly shaders don't have any normal passes - if (stage == 0 && !shader.isSky) - shader.sort = SS_FOG; - - // determine which stage iterator function is appropriate - ComputeStageIteratorFunc(); - - return GeneratePermanentShader(); -} - -//======================================================================================== - -/* -==================== -FindShaderInShaderText - -Scans the combined text description of all the shader files for -the given shader name. - -return NULL if not found - -If found, it will return a valid shader -===================== -*/ -static char *FindShaderInShaderText( const char *shadername ) { - - char *token, *p; - - int i, hash; - - hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH); - - if(shaderTextHashTable[hash]) - { - for (i = 0; shaderTextHashTable[hash][i]; i++) - { - p = shaderTextHashTable[hash][i]; - token = COM_ParseExt(&p, qtrue); - - if(!Q_stricmp(token, shadername)) - return p; - } - } - - p = s_shaderText; - - if ( !p ) { - return NULL; - } - - // look for label - while ( 1 ) { - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - if ( !Q_stricmp( token, shadername ) ) { - return p; - } - else { - // skip the definition - SkipBracedSection( &p, 0 ); - } - } - - return NULL; -} - - -/* -================== -R_FindShaderByName - -Will always return a valid shader, but it might be the -default shader if the real one can't be found. -================== -*/ -shader_t *R_FindShaderByName( const char *name ) { - char strippedName[MAX_QPATH]; - int hash; - shader_t *sh; - - if ( (name==NULL) || (name[0] == 0) ) { - return tr.defaultShader; - } - - COM_StripExtension(name, strippedName, sizeof(strippedName)); - - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - - // - // see if the shader is already loaded - // - for (sh=hashTable[hash]; sh; sh=sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if (Q_stricmp(sh->name, strippedName) == 0) { - // match found - return sh; - } - } - - return tr.defaultShader; -} - - -/* -=============== -R_FindShader - -Will always return a valid shader, but it might be the -default shader if the real one can't be found. - -In the interest of not requiring an explicit shader text entry to -be defined for every single image used in the game, three default -shader behaviors can be auto-created for any image: - -If lightmapIndex == LIGHTMAP_NONE, then the image will have -dynamic diffuse lighting applied to it, as apropriate for most -entity skin surfaces. - -If lightmapIndex == LIGHTMAP_2D, then the image will be used -for 2D rendering unless an explicit shader is found - -If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use -the vertex rgba modulate values, as apropriate for misc_model -pre-lit surfaces. - -Other lightmapIndex values will have a lightmap stage created -and src*dest blending applied with the texture, as apropriate for -most world construction surfaces. - -=============== -*/ -shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) { - char strippedName[MAX_QPATH]; - int i, hash; - char *shaderText; - image_t *image; - shader_t *sh; - - if ( name[0] == 0 ) { - return tr.defaultShader; - } - - // use (fullbright) vertex lighting if the bsp file doesn't have - // lightmaps - if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) { - lightmapIndex = LIGHTMAP_BY_VERTEX; - } else if ( lightmapIndex < LIGHTMAP_2D ) { - // negative lightmap indexes cause stray pointers (think tr.lightmaps[lightmapIndex]) - ri.Printf( PRINT_WARNING, "WARNING: shader '%s' has invalid lightmap index of %d\n", name, lightmapIndex ); - lightmapIndex = LIGHTMAP_BY_VERTEX; - } - - COM_StripExtension(name, strippedName, sizeof(strippedName)); - - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - - // - // see if the shader is already loaded - // - for (sh = hashTable[hash]; sh; sh = sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) && - !Q_stricmp(sh->name, strippedName)) { - // match found - return sh; - } - } - - // clear the global shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - Q_strncpyz(shader.name, strippedName, sizeof(shader.name)); - shader.lightmapIndex = lightmapIndex; - for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) { - stages[i].bundle[0].texMods = texMods[i]; - } - - // FIXME: set these "need" values apropriately - shader.needsNormal = qtrue; - shader.needsST1 = qtrue; - shader.needsST2 = qtrue; - shader.needsColor = qtrue; - - // - // attempt to define shader from an explicit parameter file - // - shaderText = FindShaderInShaderText( strippedName ); - if ( shaderText ) { - // enable this when building a pak file to get a global list - // of all explicit shaders - if ( r_printShaders->integer ) { - ri.Printf( PRINT_ALL, "*SHADER* %s\n", name ); - } - - if ( !ParseShader( &shaderText ) ) { - // had errors, so use default shader - shader.defaultShader = qtrue; - } - sh = FinishShader(); - return sh; - } - - - // - // if not defined in the in-memory shader descriptions, - // look for a single supported image file - // - { - imgFlags_t flags; - - flags = IMGFLAG_NONE; - - if (mipRawImage) - { - flags |= IMGFLAG_MIPMAP | IMGFLAG_PICMIP; - } - else - { - flags |= IMGFLAG_CLAMPTOEDGE; - } - - image = R_FindImageFile( name, IMGTYPE_COLORALPHA, flags ); - if ( !image ) { - ri.Printf( PRINT_DEVELOPER, "Couldn't find image file for shader %s\n", name ); - shader.defaultShader = qtrue; - return FinishShader(); - } - } - - // - // create the default shading commands - // - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - // dynamic colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { - // explicit colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_EXACT_VERTEX; - stages[0].alphaGen = AGEN_SKIP; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { - // GUI elements - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_VERTEX; - stages[0].alphaGen = AGEN_VERTEX; - stages[0].stateBits = GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { - // fullbright level - stages[0].bundle[0].image[0] = tr.whiteImage; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } else { - // two pass lightmap - stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - stages[0].bundle[0].isLightmap = qtrue; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation - // for identitylight - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } - - return FinishShader(); -} - - -qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage) { - int i, hash; - shader_t *sh; - - hash = generateHashValue(name, FILE_HASH_SIZE); - - // probably not necessary since this function - // only gets called from tr_font.c with lightmapIndex == LIGHTMAP_2D - // but better safe than sorry. - if ( lightmapIndex >= tr.numLightmaps ) { - lightmapIndex = LIGHTMAP_WHITEIMAGE; - } - - // - // see if the shader is already loaded - // - for (sh=hashTable[hash]; sh; sh=sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) && - // index by name - !Q_stricmp(sh->name, name)) { - // match found - return sh->index; - } - } - - // clear the global shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - Q_strncpyz(shader.name, name, sizeof(shader.name)); - shader.lightmapIndex = lightmapIndex; - for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) { - stages[i].bundle[0].texMods = texMods[i]; - } - - // FIXME: set these "need" values apropriately - shader.needsNormal = qtrue; - shader.needsST1 = qtrue; - shader.needsST2 = qtrue; - shader.needsColor = qtrue; - - // - // create the default shading commands - // - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - // dynamic colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { - // explicit colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_EXACT_VERTEX; - stages[0].alphaGen = AGEN_SKIP; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { - // GUI elements - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_VERTEX; - stages[0].alphaGen = AGEN_VERTEX; - stages[0].stateBits = GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { - // fullbright level - stages[0].bundle[0].image[0] = tr.whiteImage; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } else { - // two pass lightmap - stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - stages[0].bundle[0].isLightmap = qtrue; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation - // for identitylight - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } - - sh = FinishShader(); - return sh->index; -} - - -/* -==================== -RE_RegisterShader - -This is the exported shader entry point for the rest of the system -It will always return an index that will be valid. - -This should really only be used for explicit shaders, because there is no -way to ask for different implicit lighting modes (vertex, lightmap, etc) -==================== -*/ -qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, lightmapIndex, qtrue ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - - -/* -==================== -RE_RegisterShader - -This is the exported shader entry point for the rest of the system -It will always return an index that will be valid. - -This should really only be used for explicit shaders, because there is no -way to ask for different implicit lighting modes (vertex, lightmap, etc) -==================== -*/ -qhandle_t RE_RegisterShader( const char *name ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, LIGHTMAP_2D, qtrue ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - - -/* -==================== -RE_RegisterShaderNoMip - -For menu graphics that should never be picmiped -==================== -*/ -qhandle_t RE_RegisterShaderNoMip( const char *name ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, LIGHTMAP_2D, qfalse ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - -/* -==================== -R_GetShaderByHandle - -When a handle is passed in by another module, this range checks -it and returns a valid (possibly default) shader_t to be used internally. -==================== -*/ -shader_t *R_GetShaderByHandle( qhandle_t hShader ) { - if ( hShader < 0 ) { - ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); - return tr.defaultShader; - } - if ( hShader >= tr.numShaders ) { - ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); - return tr.defaultShader; - } - return tr.shaders[hShader]; -} - -/* -=============== -R_ShaderList_f - -Dump information on all valid shaders to the console -A second parameter will cause it to print in sorted order -=============== -*/ -void R_ShaderList_f (void) { - int i; - int count; - shader_t *shader; - - ri.Printf (PRINT_ALL, "-----------------------\n"); - - count = 0; - for ( i = 0 ; i < tr.numShaders ; i++ ) { - if ( ri.Cmd_Argc() > 1 ) { - shader = tr.sortedShaders[i]; - } else { - shader = tr.shaders[i]; - } - - ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses ); - - if (shader->lightmapIndex >= 0 ) { - ri.Printf (PRINT_ALL, "L "); - } else { - ri.Printf (PRINT_ALL, " "); - } - if ( shader->multitextureEnv == GL_ADD ) { - ri.Printf( PRINT_ALL, "MT(a) " ); - } else if ( shader->multitextureEnv == GL_MODULATE ) { - ri.Printf( PRINT_ALL, "MT(m) " ); - } else if ( shader->multitextureEnv == GL_DECAL ) { - ri.Printf( PRINT_ALL, "MT(d) " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - if ( shader->explicitlyDefined ) { - ri.Printf( PRINT_ALL, "E " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - - if ( shader->optimalStageIteratorFunc == RB_StageIteratorGeneric ) { - ri.Printf( PRINT_ALL, "gen " ); - } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorSky ) { - ri.Printf( PRINT_ALL, "sky " ); - } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorLightmappedMultitexture ) { - ri.Printf( PRINT_ALL, "lmmt" ); - } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorVertexLitTexture ) { - ri.Printf( PRINT_ALL, "vlt " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - - if ( shader->defaultShader ) { - ri.Printf (PRINT_ALL, ": %s (DEFAULTED)\n", shader->name); - } else { - ri.Printf (PRINT_ALL, ": %s\n", shader->name); - } - count++; - } - ri.Printf (PRINT_ALL, "%i total shaders\n", count); - ri.Printf (PRINT_ALL, "------------------\n"); -} - -/* -==================== -ScanAndLoadShaderFiles - -Finds and loads all .shader files, combining them into -a single large text block that can be scanned for shader names -===================== -*/ -#define MAX_SHADER_FILES 4096 -static void ScanAndLoadShaderFiles( void ) -{ - char **shaderFiles; - char *buffers[MAX_SHADER_FILES]; - char *p; - int numShaderFiles; - int i; - char *oldp, *token, *hashMem, *textEnd; - int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size; - char shaderName[MAX_QPATH]; - int shaderLine; - - long sum = 0, summand; - // scan for shader files - shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles ); - - if ( !shaderFiles || !numShaderFiles ) - { - ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" ); - return; - } - - if ( numShaderFiles > MAX_SHADER_FILES ) { - numShaderFiles = MAX_SHADER_FILES; - } - - // load and parse shader files - for ( i = 0; i < numShaderFiles; i++ ) - { - char filename[MAX_QPATH]; - - Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] ); - ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename ); - summand = ri.FS_ReadFile( filename, (void **)&buffers[i] ); - - if ( !buffers[i] ) - ri.Error( ERR_DROP, "Couldn't load %s", filename ); - - // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders. - p = buffers[i]; - COM_BeginParseSession(filename); - while(1) - { - token = COM_ParseExt(&p, qtrue); - - if(!*token) - break; - - Q_strncpyz(shaderName, token, sizeof(shaderName)); - shaderLine = COM_GetCurrentParseLine(); - - token = COM_ParseExt(&p, qtrue); - if(token[0] != '{' || token[1] != '\0') - { - ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing opening brace", - filename, shaderName, shaderLine); - if (token[0]) - { - ri.Printf(PRINT_WARNING, " (found \"%s\" on line %d)", token, COM_GetCurrentParseLine()); - } - ri.Printf(PRINT_WARNING, ".\n"); - ri.FS_FreeFile(buffers[i]); - buffers[i] = NULL; - break; - } - - if(!SkipBracedSection(&p, 1)) - { - ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n", - filename, shaderName, shaderLine); - ri.FS_FreeFile(buffers[i]); - buffers[i] = NULL; - break; - } - } - - - if (buffers[i]) - sum += summand; - } - - // build single large buffer - s_shaderText = ri.Hunk_Alloc( sum + numShaderFiles*2, h_low ); - s_shaderText[ 0 ] = '\0'; - textEnd = s_shaderText; - - // free in reverse order, so the temp files are all dumped - for ( i = numShaderFiles - 1; i >= 0 ; i-- ) - { - if ( !buffers[i] ) - continue; - - strcat( textEnd, buffers[i] ); - strcat( textEnd, "\n" ); - textEnd += strlen( textEnd ); - ri.FS_FreeFile( buffers[i] ); - } - - COM_Compress( s_shaderText ); - - // free up memory - ri.FS_FreeFileList( shaderFiles ); - - Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes)); - size = 0; - - p = s_shaderText; - // look for shader names - while ( 1 ) { - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - hash = generateHashValue(token, MAX_SHADERTEXT_HASH); - shaderTextHashTableSizes[hash]++; - size++; - SkipBracedSection(&p, 0); - } - - size += MAX_SHADERTEXT_HASH; - - hashMem = ri.Hunk_Alloc( size * sizeof(char *), h_low ); - - for (i = 0; i < MAX_SHADERTEXT_HASH; i++) { - shaderTextHashTable[i] = (char **) hashMem; - hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *)); - } - - Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes)); - - p = s_shaderText; - // look for shader names - while ( 1 ) { - oldp = p; - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - hash = generateHashValue(token, MAX_SHADERTEXT_HASH); - shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp; - - SkipBracedSection(&p, 0); - } - - return; - -} - - -/* -==================== -CreateInternalShaders -==================== -*/ -static void CreateInternalShaders( void ) { - tr.numShaders = 0; - - // init the default shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - - Q_strncpyz( shader.name, "", sizeof( shader.name ) ); - - shader.lightmapIndex = LIGHTMAP_NONE; - stages[0].bundle[0].image[0] = tr.defaultImage; - stages[0].active = qtrue; - stages[0].stateBits = GLS_DEFAULT; - tr.defaultShader = FinishShader(); - - // shadow shader is just a marker - Q_strncpyz( shader.name, "", sizeof( shader.name ) ); - shader.sort = SS_STENCIL_SHADOW; - tr.shadowShader = FinishShader(); -} - -static void CreateExternalShaders( void ) { - tr.projectionShadowShader = R_FindShader( "projectionShadow", LIGHTMAP_NONE, qtrue ); - tr.flareShader = R_FindShader( "flareShader", LIGHTMAP_NONE, qtrue ); - - // Hack to make fogging work correctly on flares. Fog colors are calculated - // in tr_flare.c already. - if(!tr.flareShader->defaultShader) - { - int index; - - for(index = 0; index < tr.flareShader->numUnfoggedPasses; index++) - { - tr.flareShader->stages[index]->adjustColorsForFog = ACFF_NONE; - tr.flareShader->stages[index]->stateBits |= GLS_DEPTHTEST_DISABLE; - } - } - - tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue ); -} - -/* -================== -R_InitShaders -================== -*/ -void R_InitShaders( void ) { - ri.Printf( PRINT_ALL, "Initializing Shaders\n" ); - - Com_Memset(hashTable, 0, sizeof(hashTable)); - - CreateInternalShaders(); - - ScanAndLoadShaderFiles(); - - CreateExternalShaders(); -} diff --git a/code/renderergl1/tr_shadows.c b/code/renderergl1/tr_shadows.c deleted file mode 100644 index f412b00d3e..0000000000 --- a/code/renderergl1/tr_shadows.c +++ /dev/null @@ -1,343 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - - -/* - - for a projection shadow: - - point[x] += light vector * ( z - shadow plane ) - point[y] += - point[z] = shadow plane - - 1 0 light[x] / light[z] - -*/ - -typedef struct { - int i2; - int facing; -} edgeDef_t; - -#define MAX_EDGE_DEFS 32 - -static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS]; -static int numEdgeDefs[SHADER_MAX_VERTEXES]; -static int facing[SHADER_MAX_INDEXES/3]; - -void R_AddEdgeDef( int i1, int i2, int facing ) { - int c; - - c = numEdgeDefs[ i1 ]; - if ( c == MAX_EDGE_DEFS ) { - return; // overflow - } - edgeDefs[ i1 ][ c ].i2 = i2; - edgeDefs[ i1 ][ c ].facing = facing; - - numEdgeDefs[ i1 ]++; -} - -void R_RenderShadowEdges( void ) { - int i; - -#if 0 - int numTris; - - // dumb way -- render every triangle's edges - numTris = tess.numIndexes / 3; - - for ( i = 0 ; i < numTris ; i++ ) { - int i1, i2, i3; - - if ( !facing[i] ) { - continue; - } - - i1 = tess.indexes[ i*3 + 0 ]; - i2 = tess.indexes[ i*3 + 1 ]; - i3 = tess.indexes[ i*3 + 2 ]; - - qglBegin( GL_TRIANGLE_STRIP ); - qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i3 ] ); - qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); - qglEnd(); - } -#else - int c, c2; - int j, k; - int i2; - int c_edges, c_rejected; - int hit[2]; - - // an edge is NOT a silhouette edge if its face doesn't face the light, - // or if it has a reverse paired edge that also faces the light. - // A well behaved polyhedron would have exactly two faces for each edge, - // but lots of models have dangling edges or overfanned edges - c_edges = 0; - c_rejected = 0; - - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - c = numEdgeDefs[ i ]; - for ( j = 0 ; j < c ; j++ ) { - if ( !edgeDefs[ i ][ j ].facing ) { - continue; - } - - hit[0] = 0; - hit[1] = 0; - - i2 = edgeDefs[ i ][ j ].i2; - c2 = numEdgeDefs[ i2 ]; - for ( k = 0 ; k < c2 ; k++ ) { - if ( edgeDefs[ i2 ][ k ].i2 == i ) { - hit[ edgeDefs[ i2 ][ k ].facing ]++; - } - } - - // if it doesn't share the edge with another front facing - // triangle, it is a sil edge - if ( hit[ 1 ] == 0 ) { - qglBegin( GL_TRIANGLE_STRIP ); - qglVertex3fv( tess.xyz[ i ] ); - qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); - qglEnd(); - c_edges++; - } else { - c_rejected++; - } - } - } -#endif -} - -/* -================= -RB_ShadowTessEnd - -triangleFromEdge[ v1 ][ v2 ] - - - set triangle from edge( v1, v2, tri ) - if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { - } -================= -*/ -void RB_ShadowTessEnd( void ) { - int i; - int numTris; - vec3_t lightDir; - GLboolean rgba[4]; - - // we can only do this if we have enough space in the vertex buffers - if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { - return; - } - - if ( glConfig.stencilBits < 4 ) { - return; - } - - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); - - // project vertexes away from light direction - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); - } - - // decide which triangles face the light - Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes ); - - numTris = tess.numIndexes / 3; - for ( i = 0 ; i < numTris ; i++ ) { - int i1, i2, i3; - vec3_t d1, d2, normal; - float *v1, *v2, *v3; - float d; - - i1 = tess.indexes[ i*3 + 0 ]; - i2 = tess.indexes[ i*3 + 1 ]; - i3 = tess.indexes[ i*3 + 2 ]; - - v1 = tess.xyz[ i1 ]; - v2 = tess.xyz[ i2 ]; - v3 = tess.xyz[ i3 ]; - - VectorSubtract( v2, v1, d1 ); - VectorSubtract( v3, v1, d2 ); - CrossProduct( d1, d2, normal ); - - d = DotProduct( normal, lightDir ); - if ( d > 0 ) { - facing[ i ] = 1; - } else { - facing[ i ] = 0; - } - - // create the edges - R_AddEdgeDef( i1, i2, facing[ i ] ); - R_AddEdgeDef( i2, i3, facing[ i ] ); - R_AddEdgeDef( i3, i1, facing[ i ] ); - } - - // draw the silhouette edges - - GL_Bind( tr.whiteImage ); - qglEnable( GL_CULL_FACE ); - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - qglColor3f( 0.2f, 0.2f, 0.2f ); - - // don't write to the color buffer - qglGetBooleanv(GL_COLOR_WRITEMASK, rgba); - qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); - - qglEnable( GL_STENCIL_TEST ); - qglStencilFunc( GL_ALWAYS, 1, 255 ); - - // mirrors have the culling order reversed - if ( backEnd.viewParms.isMirror ) { - qglCullFace( GL_FRONT ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); - - R_RenderShadowEdges(); - - qglCullFace( GL_BACK ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); - - R_RenderShadowEdges(); - } else { - qglCullFace( GL_BACK ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); - - R_RenderShadowEdges(); - - qglCullFace( GL_FRONT ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); - - R_RenderShadowEdges(); - } - - - // reenable writing to the color buffer - qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); -} - - -/* -================= -RB_ShadowFinish - -Darken everything that is is a shadow volume. -We have to delay this until everything has been shadowed, -because otherwise shadows from different body parts would -overlap and double darken. -================= -*/ -void RB_ShadowFinish( void ) { - if ( r_shadows->integer != 2 ) { - return; - } - if ( glConfig.stencilBits < 4 ) { - return; - } - qglEnable( GL_STENCIL_TEST ); - qglStencilFunc( GL_NOTEQUAL, 0, 255 ); - - qglDisable (GL_CLIP_PLANE0); - qglDisable (GL_CULL_FACE); - - GL_Bind( tr.whiteImage ); - - qglLoadIdentity (); - - qglColor3f( 0.6f, 0.6f, 0.6f ); - GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); - -// qglColor3f( 1, 0, 0 ); -// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - - qglBegin( GL_QUADS ); - qglVertex3f( -100, 100, -10 ); - qglVertex3f( 100, 100, -10 ); - qglVertex3f( 100, -100, -10 ); - qglVertex3f( -100, -100, -10 ); - qglEnd (); - - qglColor4f(1,1,1,1); - qglDisable( GL_STENCIL_TEST ); -} - - -/* -================= -RB_ProjectionShadowDeform - -================= -*/ -void RB_ProjectionShadowDeform( void ) { - float *xyz; - int i; - float h; - vec3_t ground; - vec3_t light; - float groundDist; - float d; - vec3_t lightDir; - - xyz = ( float * ) tess.xyz; - - ground[0] = backEnd.or.axis[0][2]; - ground[1] = backEnd.or.axis[1][2]; - ground[2] = backEnd.or.axis[2][2]; - - groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane; - - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); - d = DotProduct( lightDir, ground ); - // don't let the shadows get too long or go negative - if ( d < 0.5 ) { - VectorMA( lightDir, (0.5 - d), ground, lightDir ); - d = DotProduct( lightDir, ground ); - } - d = 1.0 / d; - - light[0] = lightDir[0] * d; - light[1] = lightDir[1] * d; - light[2] = lightDir[2] * d; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) { - h = DotProduct( xyz, ground ) + groundDist; - - xyz[0] -= light[0] * h; - xyz[1] -= light[1] * h; - xyz[2] -= light[2] * h; - } -} diff --git a/code/renderergl1/tr_sky.c b/code/renderergl1/tr_sky.c deleted file mode 100644 index daa5ff12d6..0000000000 --- a/code/renderergl1/tr_sky.c +++ /dev/null @@ -1,794 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_sky.c -#include "tr_local.h" - -#define SKY_SUBDIVISIONS 8 -#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2) - -static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; -static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; - -/* -=================================================================================== - -POLYGON TO BOX SIDE PROJECTION - -=================================================================================== -*/ - -static vec3_t sky_clip[6] = -{ - {1,1,0}, - {1,-1,0}, - {0,-1,1}, - {0,1,1}, - {1,0,1}, - {-1,0,1} -}; - -static float sky_mins[2][6], sky_maxs[2][6]; -static float sky_min, sky_max; - -/* -================ -AddSkyPolygon -================ -*/ -static void AddSkyPolygon (int nump, vec3_t vecs) -{ - int i,j; - vec3_t v, av; - float s, t, dv; - int axis; - float *vp; - // s = [0]/[2], t = [1]/[2] - static int vec_to_st[6][3] = - { - {-2,3,1}, - {2,3,-1}, - - {1,3,2}, - {-1,3,-2}, - - {-2,-1,3}, - {-2,1,-3} - - // {-1,2,3}, - // {1,2,-3} - }; - - // decide which face it maps to - VectorCopy (vec3_origin, v); - for (i=0, vp=vecs ; i av[1] && av[0] > av[2]) - { - if (v[0] < 0) - axis = 1; - else - axis = 0; - } - else if (av[1] > av[2] && av[1] > av[0]) - { - if (v[1] < 0) - axis = 3; - else - axis = 2; - } - else - { - if (v[2] < 0) - axis = 5; - else - axis = 4; - } - - // project new texture coords - for (i=0 ; i 0) - dv = vecs[j - 1]; - else - dv = -vecs[-j - 1]; - if (dv < 0.001) - continue; // don't divide by zero - j = vec_to_st[axis][0]; - if (j < 0) - s = -vecs[-j -1] / dv; - else - s = vecs[j-1] / dv; - j = vec_to_st[axis][1]; - if (j < 0) - t = -vecs[-j -1] / dv; - else - t = vecs[j-1] / dv; - - if (s < sky_mins[0][axis]) - sky_mins[0][axis] = s; - if (t < sky_mins[1][axis]) - sky_mins[1][axis] = t; - if (s > sky_maxs[0][axis]) - sky_maxs[0][axis] = s; - if (t > sky_maxs[1][axis]) - sky_maxs[1][axis] = t; - } -} - -#define ON_EPSILON 0.1f // point on plane side epsilon -#define MAX_CLIP_VERTS 64 -/* -================ -ClipSkyPolygon -================ -*/ -static void ClipSkyPolygon (int nump, vec3_t vecs, int stage) -{ - float *norm; - float *v; - qboolean front, back; - float d, e; - float dists[MAX_CLIP_VERTS]; - int sides[MAX_CLIP_VERTS]; - vec3_t newv[2][MAX_CLIP_VERTS]; - int newc[2]; - int i, j; - - if (nump > MAX_CLIP_VERTS-2) - ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); - if (stage == 6) - { // fully clipped, so draw it - AddSkyPolygon (nump, vecs); - return; - } - - front = back = qfalse; - norm = sky_clip[stage]; - for (i=0, v = vecs ; i ON_EPSILON) - { - front = qtrue; - sides[i] = SIDE_FRONT; - } - else if (d < -ON_EPSILON) - { - back = qtrue; - sides[i] = SIDE_BACK; - } - else - sides[i] = SIDE_ON; - dists[i] = d; - } - - if (!front || !back) - { // not clipped - ClipSkyPolygon (nump, vecs, stage+1); - return; - } - - // clip it - sides[i] = sides[0]; - dists[i] = dists[0]; - VectorCopy (vecs, (vecs+(i*3)) ); - newc[0] = newc[1] = 0; - - for (i=0, v = vecs ; inumIndexes; i += 3 ) - { - for (j = 0 ; j < 3 ; j++) - { - VectorSubtract( input->xyz[input->indexes[i+j]], - backEnd.viewParms.or.origin, - p[j] ); - } - ClipSkyPolygon( 3, p[0], 0 ); - } -} - -/* -=================================================================================== - -CLOUD VERTEX GENERATION - -=================================================================================== -*/ - -/* -** MakeSkyVec -** -** Parms: s, t range from -1 to 1 -*/ -static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ ) -{ - // 1 = s, 2 = t, 3 = 2048 - static int st_to_vec[6][3] = - { - {3,-1,2}, - {-3,1,2}, - - {1,3,2}, - {-1,-3,2}, - - {-2,-1,3}, // 0 degrees yaw, look straight up - {2,-1,-3} // look straight down - }; - - vec3_t b; - int j, k; - float boxSize; - - boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - b[0] = s*boxSize; - b[1] = t*boxSize; - b[2] = boxSize; - - for (j=0 ; j<3 ; j++) - { - k = st_to_vec[axis][j]; - if (k < 0) - { - outXYZ[j] = -b[-k - 1]; - } - else - { - outXYZ[j] = b[k - 1]; - } - } - - // avoid bilerp seam - s = (s+1)*0.5; - t = (t+1)*0.5; - if (s < sky_min) - { - s = sky_min; - } - else if (s > sky_max) - { - s = sky_max; - } - - if (t < sky_min) - { - t = sky_min; - } - else if (t > sky_max) - { - t = sky_max; - } - - t = 1.0 - t; - - - if ( outSt ) - { - outSt[0] = s; - outSt[1] = t; - } -} - -static int sky_texorder[6] = {0,2,1,3,4,5}; -static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; -static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; - -static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] ) -{ - int s, t; - - GL_Bind( image ); - - for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - qglBegin( GL_TRIANGLE_STRIP ); - - for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - qglTexCoord2fv( s_skyTexCoords[t][s] ); - qglVertex3fv( s_skyPoints[t][s] ); - - qglTexCoord2fv( s_skyTexCoords[t+1][s] ); - qglVertex3fv( s_skyPoints[t+1][s] ); - } - - qglEnd(); - } -} - -static void DrawSkyBox( shader_t *shader ) -{ - int i; - - sky_min = 0; - sky_max = 1; - - Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) ); - - for (i=0 ; i<6 ; i++) - { - int sky_mins_subd[2], sky_maxs_subd[2]; - int s, t; - - sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - - if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || - ( sky_mins[1][i] >= sky_maxs[1][i] ) ) - { - continue; - } - - sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS; - sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS; - sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS; - sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS; - - if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; - - if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; - - // - // iterate through the subdivisions - // - for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - s_skyTexCoords[t][s], - s_skyPoints[t][s] ); - } - } - - DrawSkySide( shader->sky.outerbox[sky_texorder[i]], - sky_mins_subd, - sky_maxs_subd ); - } - -} - -static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes ) -{ - int s, t; - int vertexStart = tess.numVertexes; - int tHeight, sWidth; - - tHeight = maxs[1] - mins[1] + 1; - sWidth = maxs[0] - mins[0] + 1; - - for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; - tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; - - tess.numVertexes++; - - if ( tess.numVertexes >= SHADER_MAX_VERTEXES ) - { - ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()" ); - } - } - } - - // only add indexes for one pass, otherwise it would draw multiple times for each pass - if ( addIndexes ) { - for ( t = 0; t < tHeight-1; t++ ) - { - for ( s = 0; s < sWidth-1; s++ ) - { - tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); - tess.numIndexes++; - - tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); - tess.numIndexes++; - } - } - } -} - -static void FillCloudBox( const shader_t *shader, int stage ) -{ - int i; - - for ( i =0; i < 6; i++ ) - { - int sky_mins_subd[2], sky_maxs_subd[2]; - int s, t; - float MIN_T; - - if ( 1 ) // FIXME? shader->sky.fullClouds ) - { - MIN_T = -HALF_SKY_SUBDIVISIONS; - - // still don't want to draw the bottom, even if fullClouds - if ( i == 5 ) - continue; - } - else - { - switch( i ) - { - case 0: - case 1: - case 2: - case 3: - MIN_T = -1; - break; - case 5: - // don't draw clouds beneath you - continue; - case 4: // top - default: - MIN_T = -HALF_SKY_SUBDIVISIONS; - break; - } - } - - sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - - if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || - ( sky_mins[1][i] >= sky_maxs[1][i] ) ) - { - continue; - } - - sky_mins_subd[0] = ri.ftol(sky_mins[0][i] * HALF_SKY_SUBDIVISIONS); - sky_mins_subd[1] = ri.ftol(sky_mins[1][i] * HALF_SKY_SUBDIVISIONS); - sky_maxs_subd[0] = ri.ftol(sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS); - sky_maxs_subd[1] = ri.ftol(sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS); - - if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_mins_subd[1] < MIN_T ) - sky_mins_subd[1] = MIN_T; - else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; - - if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_maxs_subd[1] < MIN_T ) - sky_maxs_subd[1] = MIN_T; - else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; - - // - // iterate through the subdivisions - // - for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - NULL, - s_skyPoints[t][s] ); - - s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0]; - s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1]; - } - } - - // only add indexes for first stage - FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) ); - } -} - -/* -** R_BuildCloudData -*/ -void R_BuildCloudData( shaderCommands_t *input ) -{ - int i; - shader_t *shader; - - shader = input->shader; - - assert( shader->isSky ); - - sky_min = 1.0 / 256.0f; // FIXME: not correct? - sky_max = 255.0 / 256.0f; - - // set up for drawing - tess.numIndexes = 0; - tess.numVertexes = 0; - - if ( shader->sky.cloudHeight ) - { - for ( i = 0; i < MAX_SHADER_STAGES; i++ ) - { - if ( !tess.xstages[i] ) { - break; - } - FillCloudBox( shader, i ); - } - } -} - -/* -** R_InitSkyTexCoords -** Called when a sky shader is parsed -*/ -#define SQR( a ) ((a)*(a)) -void R_InitSkyTexCoords( float heightCloud ) -{ - int i, s, t; - float radiusWorld = 4096; - float p; - float sRad, tRad; - vec3_t skyVec; - vec3_t v; - - // init zfar so MakeSkyVec works even though - // a world hasn't been bounded - backEnd.viewParms.zFar = 1024; - - for ( i = 0; i < 6; i++ ) - { - for ( t = 0; t <= SKY_SUBDIVISIONS; t++ ) - { - for ( s = 0; s <= SKY_SUBDIVISIONS; s++ ) - { - // compute vector from view origin to sky side integral point - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - NULL, - skyVec ); - - // compute parametric value 'p' that intersects with cloud layer - p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) * - ( -2 * skyVec[2] * radiusWorld + - 2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) + - 2 * SQR( skyVec[0] ) * radiusWorld * heightCloud + - SQR( skyVec[0] ) * SQR( heightCloud ) + - 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud + - SQR( skyVec[1] ) * SQR( heightCloud ) + - 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud + - SQR( skyVec[2] ) * SQR( heightCloud ) ) ); - - s_cloudTexP[i][t][s] = p; - - // compute intersection point based on p - VectorScale( skyVec, p, v ); - v[2] += radiusWorld; - - // compute vector from world origin to intersection point 'v' - VectorNormalize( v ); - - sRad = Q_acos( v[0] ); - tRad = Q_acos( v[1] ); - - s_cloudTexCoords[i][t][s][0] = sRad; - s_cloudTexCoords[i][t][s][1] = tRad; - } - } - } -} - -//====================================================================================== - -/* -** RB_DrawSun -*/ -void RB_DrawSun( float scale, shader_t *shader ) { - float size; - float dist; - vec3_t origin, vec1, vec2; - byte sunColor[4] = { 255, 255, 255, 255 }; - - if ( !backEnd.skyRenderedThisView ) { - return; - } - - qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); - qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); - - dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - size = dist * scale; - - VectorScale( tr.sunDirection, dist, origin ); - PerpendicularVector( vec1, tr.sunDirection ); - CrossProduct( tr.sunDirection, vec1, vec2 ); - - VectorScale( vec1, size, vec1 ); - VectorScale( vec2, size, vec2 ); - - // farthest depth range - qglDepthRange( 1.0, 1.0 ); - - RB_BeginSurface( shader, 0 ); - - RB_AddQuadStamp(origin, vec1, vec2, sunColor); - - RB_EndSurface(); - - // back to normal depth range - qglDepthRange( 0.0, 1.0 ); -} - - - - -/* -================ -RB_StageIteratorSky - -All of the visible sky triangles are in tess - -Other things could be stuck in here, like birds in the sky, etc -================ -*/ -void RB_StageIteratorSky( void ) { - if ( r_fastsky->integer ) { - return; - } - - // go through all the polygons and project them onto - // the sky box to see which blocks on each side need - // to be drawn - RB_ClipSkyPolygons( &tess ); - - // r_showsky will let all the sky blocks be drawn in - // front of everything to allow developers to see how - // much sky is getting sucked in - if ( r_showsky->integer ) { - qglDepthRange( 0.0, 0.0 ); - } else { - qglDepthRange( 1.0, 1.0 ); - } - - // draw the outer skybox - if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) { - qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); - - qglPushMatrix (); - GL_State( 0 ); - qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); - - DrawSkyBox( tess.shader ); - - qglPopMatrix(); - } - - // generate the vertexes for all the clouds, which will be drawn - // by the generic shader routine - R_BuildCloudData( &tess ); - - RB_StageIteratorGeneric(); - - // draw the inner skybox - - - // back to normal depth range - qglDepthRange( 0.0, 1.0 ); - - // note that sky was drawn so we will draw a sun later - backEnd.skyRenderedThisView = qtrue; -} - diff --git a/code/renderergl1/tr_subs.c b/code/renderergl1/tr_subs.c deleted file mode 100644 index 6f4901287c..0000000000 --- a/code/renderergl1/tr_subs.c +++ /dev/null @@ -1,48 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_subs.c - common function replacements for modular renderer - -#include "tr_local.h" - -void QDECL Com_Printf( const char *msg, ... ) -{ - va_list argptr; - char text[1024]; - - va_start(argptr, msg); - Q_vsnprintf(text, sizeof(text), msg, argptr); - va_end(argptr); - - ri.Printf(PRINT_ALL, "%s", text); -} - -void QDECL Com_Error( int level, const char *error, ... ) -{ - va_list argptr; - char text[1024]; - - va_start(argptr, error); - Q_vsnprintf(text, sizeof(text), error, argptr); - va_end(argptr); - - ri.Error(level, "%s", text); -} diff --git a/code/renderergl1/tr_surface.c b/code/renderergl1/tr_surface.c deleted file mode 100644 index 1879fe2c02..0000000000 --- a/code/renderergl1/tr_surface.c +++ /dev/null @@ -1,1243 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_surf.c -#include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - -/* - - THIS ENTIRE FILE IS BACK END - -backEnd.currentEntity will be valid. - -Tess_Begin has already been called for the surface's shader. - -The modelview matrix will be set. - -It is safe to actually issue drawing commands here if you don't want to -use the shader system. -*/ - - -//============================================================================ - - -/* -============== -RB_CheckOverflow -============== -*/ -void RB_CheckOverflow( int verts, int indexes ) { - if (tess.numVertexes + verts < SHADER_MAX_VERTEXES - && tess.numIndexes + indexes < SHADER_MAX_INDEXES) { - return; - } - - RB_EndSurface(); - - if ( verts >= SHADER_MAX_VERTEXES ) { - ri.Error(ERR_DROP, "RB_CheckOverflow: verts > MAX (%d > %d)", verts, SHADER_MAX_VERTEXES ); - } - if ( indexes >= SHADER_MAX_INDEXES ) { - ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES ); - } - - RB_BeginSurface(tess.shader, tess.fogNum ); -} - - -/* -============== -RB_AddQuadStampExt -============== -*/ -void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ) { - vec3_t normal; - int ndx; - - RB_CHECKOVERFLOW( 4, 6 ); - - ndx = tess.numVertexes; - - // triangle indexes for a simple quad - tess.indexes[ tess.numIndexes ] = ndx; - tess.indexes[ tess.numIndexes + 1 ] = ndx + 1; - tess.indexes[ tess.numIndexes + 2 ] = ndx + 3; - - tess.indexes[ tess.numIndexes + 3 ] = ndx + 3; - tess.indexes[ tess.numIndexes + 4 ] = ndx + 1; - tess.indexes[ tess.numIndexes + 5 ] = ndx + 2; - - tess.xyz[ndx][0] = origin[0] + left[0] + up[0]; - tess.xyz[ndx][1] = origin[1] + left[1] + up[1]; - tess.xyz[ndx][2] = origin[2] + left[2] + up[2]; - - tess.xyz[ndx+1][0] = origin[0] - left[0] + up[0]; - tess.xyz[ndx+1][1] = origin[1] - left[1] + up[1]; - tess.xyz[ndx+1][2] = origin[2] - left[2] + up[2]; - - tess.xyz[ndx+2][0] = origin[0] - left[0] - up[0]; - tess.xyz[ndx+2][1] = origin[1] - left[1] - up[1]; - tess.xyz[ndx+2][2] = origin[2] - left[2] - up[2]; - - tess.xyz[ndx+3][0] = origin[0] + left[0] - up[0]; - tess.xyz[ndx+3][1] = origin[1] + left[1] - up[1]; - tess.xyz[ndx+3][2] = origin[2] + left[2] - up[2]; - - - // constant normal all the way around - VectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal ); - - tess.normal[ndx][0] = tess.normal[ndx+1][0] = tess.normal[ndx+2][0] = tess.normal[ndx+3][0] = normal[0]; - tess.normal[ndx][1] = tess.normal[ndx+1][1] = tess.normal[ndx+2][1] = tess.normal[ndx+3][1] = normal[1]; - tess.normal[ndx][2] = tess.normal[ndx+1][2] = tess.normal[ndx+2][2] = tess.normal[ndx+3][2] = normal[2]; - - // standard square texture coordinates - tess.texCoords[ndx][0][0] = tess.texCoords[ndx][1][0] = s1; - tess.texCoords[ndx][0][1] = tess.texCoords[ndx][1][1] = t1; - - tess.texCoords[ndx+1][0][0] = tess.texCoords[ndx+1][1][0] = s2; - tess.texCoords[ndx+1][0][1] = tess.texCoords[ndx+1][1][1] = t1; - - tess.texCoords[ndx+2][0][0] = tess.texCoords[ndx+2][1][0] = s2; - tess.texCoords[ndx+2][0][1] = tess.texCoords[ndx+2][1][1] = t2; - - tess.texCoords[ndx+3][0][0] = tess.texCoords[ndx+3][1][0] = s1; - tess.texCoords[ndx+3][0][1] = tess.texCoords[ndx+3][1][1] = t2; - - // constant color all the way around - // should this be identity and let the shader specify from entity? - * ( unsigned int * ) &tess.vertexColors[ndx] = - * ( unsigned int * ) &tess.vertexColors[ndx+1] = - * ( unsigned int * ) &tess.vertexColors[ndx+2] = - * ( unsigned int * ) &tess.vertexColors[ndx+3] = - * ( unsigned int * )color; - - - tess.numVertexes += 4; - tess.numIndexes += 6; -} - -/* -============== -RB_AddQuadStamp -============== -*/ -void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ) { - RB_AddQuadStampExt( origin, left, up, color, 0, 0, 1, 1 ); -} - -/* -============== -RB_SurfaceSprite -============== -*/ -static void RB_SurfaceSprite( void ) { - vec3_t left, up; - float radius; - - // calculate the xyz locations for the four corners - radius = backEnd.currentEntity->e.radius; - if ( backEnd.currentEntity->e.rotation == 0 ) { - VectorScale( backEnd.viewParms.or.axis[1], radius, left ); - VectorScale( backEnd.viewParms.or.axis[2], radius, up ); - } else { - float s, c; - float ang; - - ang = M_PI * backEnd.currentEntity->e.rotation / 180; - s = sin( ang ); - c = cos( ang ); - - VectorScale( backEnd.viewParms.or.axis[1], c * radius, left ); - VectorMA( left, -s * radius, backEnd.viewParms.or.axis[2], left ); - - VectorScale( backEnd.viewParms.or.axis[2], c * radius, up ); - VectorMA( up, s * radius, backEnd.viewParms.or.axis[1], up ); - } - if ( backEnd.viewParms.isMirror ) { - VectorSubtract( vec3_origin, left, left ); - } - - RB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, backEnd.currentEntity->e.shaderRGBA ); -} - - -/* -============= -RB_SurfacePolychain -============= -*/ -static void RB_SurfacePolychain( srfPoly_t *p ) { - int i; - int numv; - - RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) ); - - // fan triangles into the tess array - numv = tess.numVertexes; - for ( i = 0; i < p->numVerts; i++ ) { - VectorCopy( p->verts[i].xyz, tess.xyz[numv] ); - tess.texCoords[numv][0][0] = p->verts[i].st[0]; - tess.texCoords[numv][0][1] = p->verts[i].st[1]; - *(int *)&tess.vertexColors[numv] = *(int *)p->verts[ i ].modulate; - - numv++; - } - - // generate fan indexes into the tess array - for ( i = 0; i < p->numVerts-2; i++ ) { - tess.indexes[tess.numIndexes + 0] = tess.numVertexes; - tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1; - tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2; - tess.numIndexes += 3; - } - - tess.numVertexes = numv; -} - - -/* -============= -RB_SurfaceTriangles -============= -*/ -static void RB_SurfaceTriangles( srfTriangles_t *srf ) { - int i; - drawVert_t *dv; - float *xyz, *normal, *texCoords; - byte *color; - int dlightBits; - qboolean needsNormal; - - dlightBits = srf->dlightBits; - tess.dlightBits |= dlightBits; - - RB_CHECKOVERFLOW( srf->numVerts, srf->numIndexes ); - - for ( i = 0 ; i < srf->numIndexes ; i += 3 ) { - tess.indexes[ tess.numIndexes + i + 0 ] = tess.numVertexes + srf->indexes[ i + 0 ]; - tess.indexes[ tess.numIndexes + i + 1 ] = tess.numVertexes + srf->indexes[ i + 1 ]; - tess.indexes[ tess.numIndexes + i + 2 ] = tess.numVertexes + srf->indexes[ i + 2 ]; - } - tess.numIndexes += srf->numIndexes; - - dv = srf->verts; - xyz = tess.xyz[ tess.numVertexes ]; - normal = tess.normal[ tess.numVertexes ]; - texCoords = tess.texCoords[ tess.numVertexes ][0]; - color = tess.vertexColors[ tess.numVertexes ]; - needsNormal = tess.shader->needsNormal; - - for ( i = 0 ; i < srf->numVerts ; i++, dv++, xyz += 4, normal += 4, texCoords += 4, color += 4 ) { - xyz[0] = dv->xyz[0]; - xyz[1] = dv->xyz[1]; - xyz[2] = dv->xyz[2]; - - if ( needsNormal ) { - normal[0] = dv->normal[0]; - normal[1] = dv->normal[1]; - normal[2] = dv->normal[2]; - } - - texCoords[0] = dv->st[0]; - texCoords[1] = dv->st[1]; - - texCoords[2] = dv->lightmap[0]; - texCoords[3] = dv->lightmap[1]; - - *(int *)color = *(int *)dv->color; - } - - for ( i = 0 ; i < srf->numVerts ; i++ ) { - tess.vertexDlightBits[ tess.numVertexes + i] = dlightBits; - } - - tess.numVertexes += srf->numVerts; -} - - - -/* -============== -RB_SurfaceBeam -============== -*/ -static void RB_SurfaceBeam( void ) -{ -#define NUM_BEAM_SEGS 6 - refEntity_t *e; - int i; - vec3_t perpvec; - vec3_t direction, normalized_direction; - vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS]; - vec3_t oldorigin, origin; - - e = &backEnd.currentEntity->e; - - oldorigin[0] = e->oldorigin[0]; - oldorigin[1] = e->oldorigin[1]; - oldorigin[2] = e->oldorigin[2]; - - origin[0] = e->origin[0]; - origin[1] = e->origin[1]; - origin[2] = e->origin[2]; - - normalized_direction[0] = direction[0] = oldorigin[0] - origin[0]; - normalized_direction[1] = direction[1] = oldorigin[1] - origin[1]; - normalized_direction[2] = direction[2] = oldorigin[2] - origin[2]; - - if ( VectorNormalize( normalized_direction ) == 0 ) - return; - - PerpendicularVector( perpvec, normalized_direction ); - - VectorScale( perpvec, 4, perpvec ); - - for ( i = 0; i < NUM_BEAM_SEGS ; i++ ) - { - RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i ); -// VectorAdd( start_points[i], origin, start_points[i] ); - VectorAdd( start_points[i], direction, end_points[i] ); - } - - GL_Bind( tr.whiteImage ); - - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - qglColor3f( 1, 0, 0 ); - - qglBegin( GL_TRIANGLE_STRIP ); - for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) { - qglVertex3fv( start_points[ i % NUM_BEAM_SEGS] ); - qglVertex3fv( end_points[ i % NUM_BEAM_SEGS] ); - } - qglEnd(); -} - -//================================================================================ - -static void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, float len, float spanWidth ) -{ - float spanWidth2; - int vbase; - float t = len / 256.0f; - - RB_CHECKOVERFLOW( 4, 6 ); - - vbase = tess.numVertexes; - - spanWidth2 = -spanWidth; - - // FIXME: use quad stamp? - VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25; - tess.numVertexes++; - - VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; - tess.numVertexes++; - - VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] ); - - tess.texCoords[tess.numVertexes][0][0] = t; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; - tess.numVertexes++; - - VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = t; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = vbase; - tess.indexes[tess.numIndexes++] = vbase + 1; - tess.indexes[tess.numIndexes++] = vbase + 2; - - tess.indexes[tess.numIndexes++] = vbase + 2; - tess.indexes[tess.numIndexes++] = vbase + 1; - tess.indexes[tess.numIndexes++] = vbase + 3; -} - -static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, const vec3_t right, const vec3_t up ) -{ - int i; - vec3_t pos[4]; - vec3_t v; - int spanWidth = r_railWidth->integer; - float c, s; - float scale; - - if ( numSegs > 1 ) - numSegs--; - if ( !numSegs ) - return; - - scale = 0.25; - - for ( i = 0; i < 4; i++ ) - { - c = cos( DEG2RAD( 45 + i * 90 ) ); - s = sin( DEG2RAD( 45 + i * 90 ) ); - v[0] = ( right[0] * c + up[0] * s ) * scale * spanWidth; - v[1] = ( right[1] * c + up[1] * s ) * scale * spanWidth; - v[2] = ( right[2] * c + up[2] * s ) * scale * spanWidth; - VectorAdd( start, v, pos[i] ); - - if ( numSegs > 1 ) - { - // offset by 1 segment if we're doing a long distance shot - VectorAdd( pos[i], dir, pos[i] ); - } - } - - for ( i = 0; i < numSegs; i++ ) - { - int j; - - RB_CHECKOVERFLOW( 4, 6 ); - - for ( j = 0; j < 4; j++ ) - { - VectorCopy( pos[j], tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = ( j < 2 ); - tess.texCoords[tess.numVertexes][0][1] = ( j && j != 3 ); - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; - tess.numVertexes++; - - VectorAdd( pos[j], dir, pos[j] ); - } - - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 0; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 2; - } -} - -/* -** RB_SurfaceRailRinges -*/ -static void RB_SurfaceRailRings( void ) { - refEntity_t *e; - int numSegs; - int len; - vec3_t vec; - vec3_t right, up; - vec3_t start, end; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, start ); - VectorCopy( e->origin, end ); - - // compute variables - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - MakeNormalVectors( vec, right, up ); - numSegs = ( len ) / r_railSegmentLength->value; - if ( numSegs <= 0 ) { - numSegs = 1; - } - - VectorScale( vec, r_railSegmentLength->value, vec ); - - DoRailDiscs( numSegs, start, vec, right, up ); -} - -/* -** RB_SurfaceRailCore -*/ -static void RB_SurfaceRailCore( void ) { - refEntity_t *e; - int len; - vec3_t right; - vec3_t vec; - vec3_t start, end; - vec3_t v1, v2; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, start ); - VectorCopy( e->origin, end ); - - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - - // compute side vector - VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); - VectorNormalize( v1 ); - VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); - VectorNormalize( v2 ); - CrossProduct( v1, v2, right ); - VectorNormalize( right ); - - DoRailCore( start, end, right, len, r_railCoreWidth->integer ); -} - -/* -** RB_SurfaceLightningBolt -*/ -static void RB_SurfaceLightningBolt( void ) { - refEntity_t *e; - int len; - vec3_t right; - vec3_t vec; - vec3_t start, end; - vec3_t v1, v2; - int i; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, end ); - VectorCopy( e->origin, start ); - - // compute variables - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - - // compute side vector - VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); - VectorNormalize( v1 ); - VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); - VectorNormalize( v2 ); - CrossProduct( v1, v2, right ); - VectorNormalize( right ); - - for ( i = 0 ; i < 4 ; i++ ) { - vec3_t temp; - - DoRailCore( start, end, right, len, 8 ); - RotatePointAroundVector( temp, vec, right, 45 ); - VectorCopy( temp, right ); - } -} - -/* -** VectorArrayNormalize -* -* The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0) -* This means that we don't have to worry about zero length or enormously long vectors. -*/ -static void VectorArrayNormalize(vec4_t *normals, unsigned int count) -{ -// assert(count); - -#if idppc - { - register float half = 0.5; - register float one = 1.0; - float *components = (float *)normals; - - // Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction, - // runs *much* faster than calling sqrt(). We'll use a single Newton-Raphson - // refinement step to get a little more precision. This seems to yeild results - // that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5). - // (That is, for the given input range of about 0.6 to 2.0). - do { - float x, y, z; - float B, y0, y1; - - x = components[0]; - y = components[1]; - z = components[2]; - components += 4; - B = x*x + y*y + z*z; - -#ifdef __GNUC__ - asm("frsqrte %0,%1" : "=f" (y0) : "f" (B)); -#else - y0 = __frsqrte(B); -#endif - y1 = y0 + half*y0*(one - B*y0*y0); - - x = x * y1; - y = y * y1; - components[-4] = x; - z = z * y1; - components[-3] = y; - components[-2] = z; - } while(count--); - } -#else // No assembly version for this architecture, or C_ONLY defined - // given the input, it's safe to call VectorNormalizeFast - while (count--) { - VectorNormalizeFast(normals[0]); - normals++; - } -#endif - -} - - - -/* -** LerpMeshVertexes -*/ -#if idppc_altivec -static void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp) -{ - short *oldXyz, *newXyz, *oldNormals, *newNormals; - float *outXyz, *outNormal; - float oldXyzScale QALIGN(16); - float newXyzScale QALIGN(16); - float oldNormalScale QALIGN(16); - float newNormalScale QALIGN(16); - int vertNum; - unsigned lat, lng; - int numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; - - newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.frame * surf->numVerts * 4); - newNormals = newXyz + 3; - - newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); - newNormalScale = 1.0 - backlerp; - - numVerts = surf->numVerts; - - if ( backlerp == 0 ) { - vector signed short newNormalsVec0; - vector signed short newNormalsVec1; - vector signed int newNormalsIntVec; - vector float newNormalsFloatVec; - vector float newXyzScaleVec; - vector unsigned char newNormalsLoadPermute; - vector unsigned char newNormalsStorePermute; - vector float zero; - - newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec); - newXyzScaleVec = *(vector float *)&newXyzScale; - newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute); - newXyzScaleVec = vec_splat(newXyzScaleVec,0); - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - zero = (vector float)vec_splat_s8(0); - // - // just copy the vertexes - // - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - newXyz += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - newNormalsVec0 = vec_ld(0,newXyz); - newNormalsVec1 = vec_ld(16,newXyz); - newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute); - newNormalsIntVec = vec_unpackh(newNormalsVec0); - newNormalsFloatVec = vec_ctf(newNormalsIntVec,0); - newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero); - newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute); - //outXyz[0] = newXyz[0] * newXyzScale; - //outXyz[1] = newXyz[1] * newXyzScale; - //outXyz[2] = newXyz[2] * newXyzScale; - - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - vec_ste(newNormalsFloatVec,0,outXyz); - vec_ste(newNormalsFloatVec,4,outXyz); - vec_ste(newNormalsFloatVec,8,outXyz); - } - } else { - // - // interpolate and copy the vertex and normal - // - oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); - oldNormals = oldXyz + 3; - - oldXyzScale = MD3_XYZ_SCALE * backlerp; - oldNormalScale = backlerp; - - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - vec3_t uncompressedOldNormal, uncompressedNewNormal; - - // interpolate the xyz - outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; - outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; - outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; - - // FIXME: interpolate lat/long instead? - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - lat = ( oldNormals[0] >> 8 ) & 0xff; - lng = ( oldNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - - uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; - outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; - outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; - -// VectorNormalize (outNormal); - } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); - } -} -#endif - -static void LerpMeshVertexes_scalar(md3Surface_t *surf, float backlerp) -{ - short *oldXyz, *newXyz, *oldNormals, *newNormals; - float *outXyz, *outNormal; - float oldXyzScale, newXyzScale; - float oldNormalScale, newNormalScale; - int vertNum; - unsigned lat, lng; - int numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; - - newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.frame * surf->numVerts * 4); - newNormals = newXyz + 3; - - newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); - newNormalScale = 1.0 - backlerp; - - numVerts = surf->numVerts; - - if ( backlerp == 0 ) { - // - // just copy the vertexes - // - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - newXyz += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - - outXyz[0] = newXyz[0] * newXyzScale; - outXyz[1] = newXyz[1] * newXyzScale; - outXyz[2] = newXyz[2] * newXyzScale; - - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - } - } else { - // - // interpolate and copy the vertex and normal - // - oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); - oldNormals = oldXyz + 3; - - oldXyzScale = MD3_XYZ_SCALE * backlerp; - oldNormalScale = backlerp; - - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - vec3_t uncompressedOldNormal, uncompressedNewNormal; - - // interpolate the xyz - outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; - outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; - outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; - - // FIXME: interpolate lat/long instead? - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - lat = ( oldNormals[0] >> 8 ) & 0xff; - lng = ( oldNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - - uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; - outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; - outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; - -// VectorNormalize (outNormal); - } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); - } -} - -static void LerpMeshVertexes(md3Surface_t *surf, float backlerp) -{ -#if idppc_altivec - if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. - LerpMeshVertexes_altivec( surf, backlerp ); - return; - } -#endif // idppc_altivec - LerpMeshVertexes_scalar( surf, backlerp ); -} - - -/* -============= -RB_SurfaceMesh -============= -*/ -static void RB_SurfaceMesh(md3Surface_t *surface) { - int j; - float backlerp; - int *triangles; - float *texCoords; - int indexes; - int Bob, Doug; - int numVerts; - - if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) { - backlerp = 0; - } else { - backlerp = backEnd.currentEntity->e.backlerp; - } - - RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles*3 ); - - LerpMeshVertexes (surface, backlerp); - - triangles = (int *) ((byte *)surface + surface->ofsTriangles); - indexes = surface->numTriangles * 3; - Bob = tess.numIndexes; - Doug = tess.numVertexes; - for (j = 0 ; j < indexes ; j++) { - tess.indexes[Bob + j] = Doug + triangles[j]; - } - tess.numIndexes += indexes; - - texCoords = (float *) ((byte *)surface + surface->ofsSt); - - numVerts = surface->numVerts; - for ( j = 0; j < numVerts; j++ ) { - tess.texCoords[Doug + j][0][0] = texCoords[j*2+0]; - tess.texCoords[Doug + j][0][1] = texCoords[j*2+1]; - // FIXME: fill in lightmapST for completeness? - } - - tess.numVertexes += surface->numVerts; - -} - - -/* -============== -RB_SurfaceFace -============== -*/ -static void RB_SurfaceFace( srfSurfaceFace_t *surf ) { - int i; - unsigned *indices, *tessIndexes; - float *v; - float *normal; - int ndx; - int Bob; - int numPoints; - int dlightBits; - - RB_CHECKOVERFLOW( surf->numPoints, surf->numIndices ); - - dlightBits = surf->dlightBits; - tess.dlightBits |= dlightBits; - - indices = ( unsigned * ) ( ( ( char * ) surf ) + surf->ofsIndices ); - - Bob = tess.numVertexes; - tessIndexes = tess.indexes + tess.numIndexes; - for ( i = surf->numIndices-1 ; i >= 0 ; i-- ) { - tessIndexes[i] = indices[i] + Bob; - } - - tess.numIndexes += surf->numIndices; - - numPoints = surf->numPoints; - - if ( tess.shader->needsNormal ) { - normal = surf->plane.normal; - for ( i = 0, ndx = tess.numVertexes; i < numPoints; i++, ndx++ ) { - VectorCopy( normal, tess.normal[ndx] ); - } - } - - for ( i = 0, v = surf->points[0], ndx = tess.numVertexes; i < numPoints; i++, v += VERTEXSIZE, ndx++ ) { - VectorCopy( v, tess.xyz[ndx]); - tess.texCoords[ndx][0][0] = v[3]; - tess.texCoords[ndx][0][1] = v[4]; - tess.texCoords[ndx][1][0] = v[5]; - tess.texCoords[ndx][1][1] = v[6]; - * ( unsigned int * ) &tess.vertexColors[ndx] = * ( unsigned int * ) &v[7]; - tess.vertexDlightBits[ndx] = dlightBits; - } - - - tess.numVertexes += surf->numPoints; -} - - -static float LodErrorForVolume( vec3_t local, float radius ) { - vec3_t world; - float d; - - // never let it go negative - if ( r_lodCurveError->value < 0 ) { - return 0; - } - - world[0] = local[0] * backEnd.or.axis[0][0] + local[1] * backEnd.or.axis[1][0] + - local[2] * backEnd.or.axis[2][0] + backEnd.or.origin[0]; - world[1] = local[0] * backEnd.or.axis[0][1] + local[1] * backEnd.or.axis[1][1] + - local[2] * backEnd.or.axis[2][1] + backEnd.or.origin[1]; - world[2] = local[0] * backEnd.or.axis[0][2] + local[1] * backEnd.or.axis[1][2] + - local[2] * backEnd.or.axis[2][2] + backEnd.or.origin[2]; - - VectorSubtract( world, backEnd.viewParms.or.origin, world ); - d = DotProduct( world, backEnd.viewParms.or.axis[0] ); - - if ( d < 0 ) { - d = -d; - } - d -= radius; - if ( d < 1 ) { - d = 1; - } - - return r_lodCurveError->value / d; -} - -/* -============= -RB_SurfaceGrid - -Just copy the grid of points and triangulate -============= -*/ -static void RB_SurfaceGrid( srfGridMesh_t *cv ) { - int i, j; - float *xyz; - float *texCoords; - float *normal; - unsigned char *color; - drawVert_t *dv; - int rows, irows, vrows; - int used; - int widthTable[MAX_GRID_SIZE]; - int heightTable[MAX_GRID_SIZE]; - float lodError; - int lodWidth, lodHeight; - int numVertexes; - int dlightBits; - int *vDlightBits; - qboolean needsNormal; - - dlightBits = cv->dlightBits; - tess.dlightBits |= dlightBits; - - // determine the allowable discrepance - lodError = LodErrorForVolume( cv->lodOrigin, cv->lodRadius ); - - // determine which rows and columns of the subdivision - // we are actually going to use - widthTable[0] = 0; - lodWidth = 1; - for ( i = 1 ; i < cv->width-1 ; i++ ) { - if ( cv->widthLodError[i] <= lodError ) { - widthTable[lodWidth] = i; - lodWidth++; - } - } - widthTable[lodWidth] = cv->width-1; - lodWidth++; - - heightTable[0] = 0; - lodHeight = 1; - for ( i = 1 ; i < cv->height-1 ; i++ ) { - if ( cv->heightLodError[i] <= lodError ) { - heightTable[lodHeight] = i; - lodHeight++; - } - } - heightTable[lodHeight] = cv->height-1; - lodHeight++; - - - // very large grids may have more points or indexes than can be fit - // in the tess structure, so we may have to issue it in multiple passes - - used = 0; - while ( used < lodHeight - 1 ) { - // see how many rows of both verts and indexes we can add without overflowing - do { - vrows = ( SHADER_MAX_VERTEXES - tess.numVertexes ) / lodWidth; - irows = ( SHADER_MAX_INDEXES - tess.numIndexes ) / ( lodWidth * 6 ); - - // if we don't have enough space for at least one strip, flush the buffer - if ( vrows < 2 || irows < 1 ) { - RB_EndSurface(); - RB_BeginSurface(tess.shader, tess.fogNum ); - } else { - break; - } - } while ( 1 ); - - rows = irows; - if ( vrows < irows + 1 ) { - rows = vrows - 1; - } - if ( used + rows > lodHeight ) { - rows = lodHeight - used; - } - - numVertexes = tess.numVertexes; - - xyz = tess.xyz[numVertexes]; - normal = tess.normal[numVertexes]; - texCoords = tess.texCoords[numVertexes][0]; - color = ( unsigned char * ) &tess.vertexColors[numVertexes]; - vDlightBits = &tess.vertexDlightBits[numVertexes]; - needsNormal = tess.shader->needsNormal; - - for ( i = 0 ; i < rows ; i++ ) { - for ( j = 0 ; j < lodWidth ; j++ ) { - dv = cv->verts + heightTable[ used + i ] * cv->width - + widthTable[ j ]; - - xyz[0] = dv->xyz[0]; - xyz[1] = dv->xyz[1]; - xyz[2] = dv->xyz[2]; - texCoords[0] = dv->st[0]; - texCoords[1] = dv->st[1]; - texCoords[2] = dv->lightmap[0]; - texCoords[3] = dv->lightmap[1]; - if ( needsNormal ) { - normal[0] = dv->normal[0]; - normal[1] = dv->normal[1]; - normal[2] = dv->normal[2]; - } - * ( unsigned int * ) color = * ( unsigned int * ) dv->color; - *vDlightBits++ = dlightBits; - xyz += 4; - normal += 4; - texCoords += 4; - color += 4; - } - } - - - // add the indexes - { - int numIndexes; - int w, h; - - h = rows - 1; - w = lodWidth - 1; - numIndexes = tess.numIndexes; - for (i = 0 ; i < h ; i++) { - for (j = 0 ; j < w ; j++) { - int v1, v2, v3, v4; - - // vertex order to be reckognized as tristrips - v1 = numVertexes + i*lodWidth + j + 1; - v2 = v1 - 1; - v3 = v2 + lodWidth; - v4 = v3 + 1; - - tess.indexes[numIndexes] = v2; - tess.indexes[numIndexes+1] = v3; - tess.indexes[numIndexes+2] = v1; - - tess.indexes[numIndexes+3] = v1; - tess.indexes[numIndexes+4] = v3; - tess.indexes[numIndexes+5] = v4; - numIndexes += 6; - } - } - - tess.numIndexes = numIndexes; - } - - tess.numVertexes += rows * lodWidth; - - used += rows - 1; - } -} - - -/* -=========================================================================== - -NULL MODEL - -=========================================================================== -*/ - -/* -=================== -RB_SurfaceAxis - -Draws x/y/z lines from the origin for orientation debugging -=================== -*/ -static void RB_SurfaceAxis( void ) { - GL_Bind( tr.whiteImage ); - GL_State( GLS_DEFAULT ); - qglLineWidth( 3 ); - qglBegin( GL_LINES ); - qglColor3f( 1,0,0 ); - qglVertex3f( 0,0,0 ); - qglVertex3f( 16,0,0 ); - qglColor3f( 0,1,0 ); - qglVertex3f( 0,0,0 ); - qglVertex3f( 0,16,0 ); - qglColor3f( 0,0,1 ); - qglVertex3f( 0,0,0 ); - qglVertex3f( 0,0,16 ); - qglEnd(); - qglLineWidth( 1 ); -} - -//=========================================================================== - -/* -==================== -RB_SurfaceEntity - -Entities that have a single procedurally generated surface -==================== -*/ -static void RB_SurfaceEntity( surfaceType_t *surfType ) { - switch( backEnd.currentEntity->e.reType ) { - case RT_SPRITE: - RB_SurfaceSprite(); - break; - case RT_BEAM: - RB_SurfaceBeam(); - break; - case RT_RAIL_CORE: - RB_SurfaceRailCore(); - break; - case RT_RAIL_RINGS: - RB_SurfaceRailRings(); - break; - case RT_LIGHTNING: - RB_SurfaceLightningBolt(); - break; - default: - RB_SurfaceAxis(); - break; - } -} - -static void RB_SurfaceBad( surfaceType_t *surfType ) { - ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" ); -} - -static void RB_SurfaceFlare(srfFlare_t *surf) -{ - if (r_flares->integer) - RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal); -} - -static void RB_SurfaceDisplayList( srfDisplayList_t *surf ) { - // all apropriate state must be set in RB_BeginSurface - // this isn't implemented yet... - qglCallList( surf->listNum ); -} - -static void RB_SurfaceSkip( void *surf ) { -} - - -void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { - (void(*)(void*))RB_SurfaceBad, // SF_BAD, - (void(*)(void*))RB_SurfaceSkip, // SF_SKIP, - (void(*)(void*))RB_SurfaceFace, // SF_FACE, - (void(*)(void*))RB_SurfaceGrid, // SF_GRID, - (void(*)(void*))RB_SurfaceTriangles, // SF_TRIANGLES, - (void(*)(void*))RB_SurfacePolychain, // SF_POLY, - (void(*)(void*))RB_SurfaceMesh, // SF_MD3, - (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR, - (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, - (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, - (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY - (void(*)(void*))RB_SurfaceDisplayList // SF_DISPLAY_LIST -}; diff --git a/code/renderergl1/tr_world.c b/code/renderergl1/tr_world.c deleted file mode 100644 index 0a2743f927..0000000000 --- a/code/renderergl1/tr_world.c +++ /dev/null @@ -1,668 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - - - -/* -================= -R_CullTriSurf - -Returns true if the grid is completely culled away. -Also sets the clipped hint bit in tess -================= -*/ -static qboolean R_CullTriSurf( srfTriangles_t *cv ) { - int boxCull; - - boxCull = R_CullLocalBox( cv->bounds ); - - if ( boxCull == CULL_OUT ) { - return qtrue; - } - return qfalse; -} - -/* -================= -R_CullGrid - -Returns true if the grid is completely culled away. -Also sets the clipped hint bit in tess -================= -*/ -static qboolean R_CullGrid( srfGridMesh_t *cv ) { - int boxCull; - int sphereCull; - - if ( r_nocurves->integer ) { - return qtrue; - } - - if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) { - sphereCull = R_CullLocalPointAndRadius( cv->localOrigin, cv->meshRadius ); - } else { - sphereCull = R_CullPointAndRadius( cv->localOrigin, cv->meshRadius ); - } - - // check for trivial reject - if ( sphereCull == CULL_OUT ) - { - tr.pc.c_sphere_cull_patch_out++; - return qtrue; - } - // check bounding box if necessary - else if ( sphereCull == CULL_CLIP ) - { - tr.pc.c_sphere_cull_patch_clip++; - - boxCull = R_CullLocalBox( cv->meshBounds ); - - if ( boxCull == CULL_OUT ) - { - tr.pc.c_box_cull_patch_out++; - return qtrue; - } - else if ( boxCull == CULL_IN ) - { - tr.pc.c_box_cull_patch_in++; - } - else - { - tr.pc.c_box_cull_patch_clip++; - } - } - else - { - tr.pc.c_sphere_cull_patch_in++; - } - - return qfalse; -} - - -/* -================ -R_CullSurface - -Tries to back face cull surfaces before they are lighted or -added to the sorting list. - -This will also allow mirrors on both sides of a model without recursion. -================ -*/ -static qboolean R_CullSurface( surfaceType_t *surface, shader_t *shader ) { - srfSurfaceFace_t *sface; - float d; - - if ( r_nocull->integer ) { - return qfalse; - } - - if ( *surface == SF_GRID ) { - return R_CullGrid( (srfGridMesh_t *)surface ); - } - - if ( *surface == SF_TRIANGLES ) { - return R_CullTriSurf( (srfTriangles_t *)surface ); - } - - if ( *surface != SF_FACE ) { - return qfalse; - } - - if ( shader->cullType == CT_TWO_SIDED ) { - return qfalse; - } - - // face culling - if ( !r_facePlaneCull->integer ) { - return qfalse; - } - - sface = ( srfSurfaceFace_t * ) surface; - d = DotProduct (tr.or.viewOrigin, sface->plane.normal); - - // don't cull exactly on the plane, because there are levels of rounding - // through the BSP, ICD, and hardware that may cause pixel gaps if an - // epsilon isn't allowed here - if ( shader->cullType == CT_FRONT_SIDED ) { - if ( d < sface->plane.dist - 8 ) { - return qtrue; - } - } else { - if ( d > sface->plane.dist + 8 ) { - return qtrue; - } - } - - return qfalse; -} - - -static int R_DlightFace( srfSurfaceFace_t *face, int dlightBits ) { - float d; - int i; - dlight_t *dl; - - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - d = DotProduct( dl->origin, face->plane.normal ) - face->plane.dist; - if ( d < -dl->radius || d > dl->radius ) { - // dlight doesn't reach the plane - dlightBits &= ~( 1 << i ); - } - } - - if ( !dlightBits ) { - tr.pc.c_dlightSurfacesCulled++; - } - - face->dlightBits = dlightBits; - return dlightBits; -} - -static int R_DlightGrid( srfGridMesh_t *grid, int dlightBits ) { - int i; - dlight_t *dl; - - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0] - || dl->origin[0] + dl->radius < grid->meshBounds[0][0] - || dl->origin[1] - dl->radius > grid->meshBounds[1][1] - || dl->origin[1] + dl->radius < grid->meshBounds[0][1] - || dl->origin[2] - dl->radius > grid->meshBounds[1][2] - || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) { - // dlight doesn't reach the bounds - dlightBits &= ~( 1 << i ); - } - } - - if ( !dlightBits ) { - tr.pc.c_dlightSurfacesCulled++; - } - - grid->dlightBits = dlightBits; - return dlightBits; -} - - -static int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) { - // FIXME: more dlight culling to trisurfs... - surf->dlightBits = dlightBits; - return dlightBits; -#if 0 - int i; - dlight_t *dl; - - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0] - || dl->origin[0] + dl->radius < grid->meshBounds[0][0] - || dl->origin[1] - dl->radius > grid->meshBounds[1][1] - || dl->origin[1] + dl->radius < grid->meshBounds[0][1] - || dl->origin[2] - dl->radius > grid->meshBounds[1][2] - || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) { - // dlight doesn't reach the bounds - dlightBits &= ~( 1 << i ); - } - } - - if ( !dlightBits ) { - tr.pc.c_dlightSurfacesCulled++; - } - - grid->dlightBits = dlightBits; - return dlightBits; -#endif -} - -/* -==================== -R_DlightSurface - -The given surface is going to be drawn, and it touches a leaf -that is touched by one or more dlights, so try to throw out -more dlights if possible. -==================== -*/ -static int R_DlightSurface( msurface_t *surf, int dlightBits ) { - if ( *surf->data == SF_FACE ) { - dlightBits = R_DlightFace( (srfSurfaceFace_t *)surf->data, dlightBits ); - } else if ( *surf->data == SF_GRID ) { - dlightBits = R_DlightGrid( (srfGridMesh_t *)surf->data, dlightBits ); - } else if ( *surf->data == SF_TRIANGLES ) { - dlightBits = R_DlightTrisurf( (srfTriangles_t *)surf->data, dlightBits ); - } else { - dlightBits = 0; - } - - if ( dlightBits ) { - tr.pc.c_dlightSurfaces++; - } - - return dlightBits; -} - - - -/* -====================== -R_AddWorldSurface -====================== -*/ -static void R_AddWorldSurface( msurface_t *surf, int dlightBits ) { - if ( surf->viewCount == tr.viewCount ) { - return; // already in this view - } - - surf->viewCount = tr.viewCount; - // FIXME: bmodel fog? - - // try to cull before dlighting or adding - if ( R_CullSurface( surf->data, surf->shader ) ) { - return; - } - - // check for dlighting - if ( dlightBits ) { - dlightBits = R_DlightSurface( surf, dlightBits ); - dlightBits = ( dlightBits != 0 ); - } - - R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits ); -} - -/* -============================================================= - - BRUSH MODELS - -============================================================= -*/ - -/* -================= -R_AddBrushModelSurfaces -================= -*/ -void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) { - bmodel_t *bmodel; - int clip; - model_t *pModel; - int i; - - pModel = R_GetModelByHandle( ent->e.hModel ); - - bmodel = pModel->bmodel; - - clip = R_CullLocalBox( bmodel->bounds ); - if ( clip == CULL_OUT ) { - return; - } - - R_SetupEntityLighting( &tr.refdef, ent ); - R_DlightBmodel( bmodel ); - - for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) { - R_AddWorldSurface( bmodel->firstSurface + i, tr.currentEntity->needDlights ); - } -} - - -/* -============================================================= - - WORLD MODEL - -============================================================= -*/ - - -/* -================ -R_RecursiveWorldNode -================ -*/ -static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) { - - do { - int newDlights[2]; - - // if the node wasn't marked as potentially visible, exit - if (node->visframe != tr.visCount) { - return; - } - - // if the bounding volume is outside the frustum, nothing - // inside can be visible OPTIMIZE: don't do this all the way to leafs? - - if ( !r_nocull->integer ) { - int r; - - if ( planeBits & 1 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~1; // all descendants will also be in front - } - } - - if ( planeBits & 2 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~2; // all descendants will also be in front - } - } - - if ( planeBits & 4 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~4; // all descendants will also be in front - } - } - - if ( planeBits & 8 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~8; // all descendants will also be in front - } - } - - } - - if ( node->contents != -1 ) { - break; - } - - // node is just a decision point, so go down both sides - // since we don't care about sort orders, just go positive to negative - - // determine which dlights are needed - newDlights[0] = 0; - newDlights[1] = 0; - if ( dlightBits ) { - int i; - - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - dlight_t *dl; - float dist; - - if ( dlightBits & ( 1 << i ) ) { - dl = &tr.refdef.dlights[i]; - dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist; - - if ( dist > -dl->radius ) { - newDlights[0] |= ( 1 << i ); - } - if ( dist < dl->radius ) { - newDlights[1] |= ( 1 << i ); - } - } - } - } - - // recurse down the children, front side first - R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0] ); - - // tail recurse - node = node->children[1]; - dlightBits = newDlights[1]; - } while ( 1 ); - - { - // leaf node, so add mark surfaces - int c; - msurface_t *surf, **mark; - - tr.pc.c_leafs++; - - // add to z buffer bounds - if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) { - tr.viewParms.visBounds[0][0] = node->mins[0]; - } - if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) { - tr.viewParms.visBounds[0][1] = node->mins[1]; - } - if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) { - tr.viewParms.visBounds[0][2] = node->mins[2]; - } - - if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) { - tr.viewParms.visBounds[1][0] = node->maxs[0]; - } - if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) { - tr.viewParms.visBounds[1][1] = node->maxs[1]; - } - if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) { - tr.viewParms.visBounds[1][2] = node->maxs[2]; - } - - // add the individual surfaces - mark = node->firstmarksurface; - c = node->nummarksurfaces; - while (c--) { - // the surface may have already been added if it - // spans multiple leafs - surf = *mark; - R_AddWorldSurface( surf, dlightBits ); - mark++; - } - } - -} - - -/* -=============== -R_PointInLeaf -=============== -*/ -static mnode_t *R_PointInLeaf( const vec3_t p ) { - mnode_t *node; - float d; - cplane_t *plane; - - if ( !tr.world ) { - ri.Error (ERR_DROP, "R_PointInLeaf: bad model"); - } - - node = tr.world->nodes; - while( 1 ) { - if (node->contents != -1) { - break; - } - plane = node->plane; - d = DotProduct (p,plane->normal) - plane->dist; - if (d > 0) { - node = node->children[0]; - } else { - node = node->children[1]; - } - } - - return node; -} - -/* -============== -R_ClusterPVS -============== -*/ -static const byte *R_ClusterPVS (int cluster) { - if (!tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) { - return tr.world->novis; - } - - return tr.world->vis + cluster * tr.world->clusterBytes; -} - -/* -================= -R_inPVS -================= -*/ -qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) { - mnode_t *leaf; - byte *vis; - - leaf = R_PointInLeaf( p1 ); - vis = ri.CM_ClusterPVS( leaf->cluster ); // why not R_ClusterPVS ?? - leaf = R_PointInLeaf( p2 ); - - if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) { - return qfalse; - } - return qtrue; -} - -/* -=============== -R_MarkLeaves - -Mark the leaves and nodes that are in the PVS for the current -cluster -=============== -*/ -static void R_MarkLeaves (void) { - const byte *vis; - mnode_t *leaf, *parent; - int i; - int cluster; - - // lockpvs lets designers walk around to determine the - // extent of the current pvs - if ( r_lockpvs->integer ) { - return; - } - - // current viewcluster - leaf = R_PointInLeaf( tr.viewParms.pvsOrigin ); - cluster = leaf->cluster; - - // if the cluster is the same and the area visibility matrix - // hasn't changed, we don't need to mark everything again - - // if r_showcluster was just turned on, remark everything - if ( tr.viewCluster == cluster && !tr.refdef.areamaskModified - && !r_showcluster->modified ) { - return; - } - - if ( r_showcluster->modified || r_showcluster->integer ) { - r_showcluster->modified = qfalse; - if ( r_showcluster->integer ) { - ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area ); - } - } - - tr.visCount++; - tr.viewCluster = cluster; - - if ( r_novis->integer || tr.viewCluster == -1 ) { - for (i=0 ; inumnodes ; i++) { - if (tr.world->nodes[i].contents != CONTENTS_SOLID) { - tr.world->nodes[i].visframe = tr.visCount; - } - } - return; - } - - vis = R_ClusterPVS (tr.viewCluster); - - for (i=0,leaf=tr.world->nodes ; inumnodes ; i++, leaf++) { - cluster = leaf->cluster; - if ( cluster < 0 || cluster >= tr.world->numClusters ) { - continue; - } - - // check general pvs - if ( !(vis[cluster>>3] & (1<<(cluster&7))) ) { - continue; - } - - // check for door connection - if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) { - continue; // not visible - } - - parent = leaf; - do { - if (parent->visframe == tr.visCount) - break; - parent->visframe = tr.visCount; - parent = parent->parent; - } while (parent); - } -} - - -/* -============= -R_AddWorldSurfaces -============= -*/ -void R_AddWorldSurfaces (void) { - if ( !r_drawworld->integer ) { - return; - } - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return; - } - - tr.currentEntityNum = REFENTITYNUM_WORLD; - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - - // determine which leaves are in the PVS / areamask - R_MarkLeaves (); - - // clear out the visible min/max - ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] ); - - // perform frustum culling and add all the potentially visible surfaces - if ( tr.refdef.num_dlights > 32 ) { - tr.refdef.num_dlights = 32 ; - } - R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1 ); -} diff --git a/code/renderergl2/glsl/bokeh_fp.glsl b/code/renderergl2/glsl/bokeh_fp.glsl deleted file mode 100644 index d08816aeff..0000000000 --- a/code/renderergl2/glsl/bokeh_fp.glsl +++ /dev/null @@ -1,70 +0,0 @@ -uniform sampler2D u_TextureMap; - -uniform vec4 u_Color; - -uniform vec2 u_InvTexRes; -varying vec2 var_TexCoords; - -void main() -{ - vec4 color; - vec2 tc; - -#if 0 - float c[7] = float[7](1.0, 0.9659258263, 0.8660254038, 0.7071067812, 0.5, 0.2588190451, 0.0); - - tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[6]); color = texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[5]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[2], c[4]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[3], c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[4], c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[5], c[1]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[6], c[0]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( c[1], -c[5]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[2], -c[4]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[3], -c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[4], -c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[5], -c[1]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[6], -c[0]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( -c[0], c[6]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[1], c[5]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[2], c[4]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[3], c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[4], c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[5], c[1]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( -c[1], -c[5]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[2], -c[4]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[3], -c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[4], -c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[5], -c[1]); color += texture2D(u_TextureMap, tc); - - gl_FragColor = color * 0.04166667 * u_Color; -#endif - - float c[5] = float[5](1.0, 0.9238795325, 0.7071067812, 0.3826834324, 0.0); - - tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[4]); color = texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[2], c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[3], c[1]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[4], c[0]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( c[1], -c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[2], -c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[3], -c[1]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[4], -c[0]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( -c[0], c[4]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[1], c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[2], c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[3], c[1]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( -c[1], -c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[2], -c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[3], -c[1]); color += texture2D(u_TextureMap, tc); - - gl_FragColor = color * 0.0625 * u_Color; -} diff --git a/code/renderergl2/glsl/bokeh_vp.glsl b/code/renderergl2/glsl/bokeh_vp.glsl deleted file mode 100644 index bdaa74af8e..0000000000 --- a/code/renderergl2/glsl/bokeh_vp.glsl +++ /dev/null @@ -1,13 +0,0 @@ -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_TexCoords; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - var_TexCoords = attr_TexCoord0.st; -} diff --git a/code/renderergl2/glsl/calclevels4x_fp.glsl b/code/renderergl2/glsl/calclevels4x_fp.glsl deleted file mode 100644 index c8cf06c710..0000000000 --- a/code/renderergl2/glsl/calclevels4x_fp.glsl +++ /dev/null @@ -1,55 +0,0 @@ -uniform sampler2D u_TextureMap; - -uniform vec4 u_Color; - -uniform vec2 u_InvTexRes; -varying vec2 var_TexCoords; - -const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721); //vec3(0.299, 0.587, 0.114); - -vec3 GetValues(vec2 offset, vec3 current) -{ - vec3 minAvgMax; - vec2 tc = var_TexCoords + u_InvTexRes * offset; minAvgMax = texture2D(u_TextureMap, tc).rgb; - -#ifdef FIRST_PASS - float lumi = max(dot(LUMINANCE_VECTOR, minAvgMax), 0.000001); - float loglumi = clamp(log2(lumi), -10.0, 10.0); - minAvgMax = vec3(loglumi * 0.05 + 0.5); -#endif - - return vec3(min(current.x, minAvgMax.x), current.y + minAvgMax.y, max(current.z, minAvgMax.z)); -} - -void main() -{ - vec3 current = vec3(1.0, 0.0, 0.0); - -#ifdef FIRST_PASS - current = GetValues(vec2( 0.0, 0.0), current); -#else - current = GetValues(vec2(-1.5, -1.5), current); - current = GetValues(vec2(-0.5, -1.5), current); - current = GetValues(vec2( 0.5, -1.5), current); - current = GetValues(vec2( 1.5, -1.5), current); - - current = GetValues(vec2(-1.5, -0.5), current); - current = GetValues(vec2(-0.5, -0.5), current); - current = GetValues(vec2( 0.5, -0.5), current); - current = GetValues(vec2( 1.5, -0.5), current); - - current = GetValues(vec2(-1.5, 0.5), current); - current = GetValues(vec2(-0.5, 0.5), current); - current = GetValues(vec2( 0.5, 0.5), current); - current = GetValues(vec2( 1.5, 0.5), current); - - current = GetValues(vec2(-1.5, 1.5), current); - current = GetValues(vec2(-0.5, 1.5), current); - current = GetValues(vec2( 0.5, 1.5), current); - current = GetValues(vec2( 1.5, 1.5), current); - - current.y *= 0.0625; -#endif - - gl_FragColor = vec4(current, 1.0f); -} diff --git a/code/renderergl2/glsl/calclevels4x_vp.glsl b/code/renderergl2/glsl/calclevels4x_vp.glsl deleted file mode 100644 index bdaa74af8e..0000000000 --- a/code/renderergl2/glsl/calclevels4x_vp.glsl +++ /dev/null @@ -1,13 +0,0 @@ -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_TexCoords; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - var_TexCoords = attr_TexCoord0.st; -} diff --git a/code/renderergl2/glsl/depthblur_fp.glsl b/code/renderergl2/glsl/depthblur_fp.glsl deleted file mode 100644 index 93895b4e17..0000000000 --- a/code/renderergl2/glsl/depthblur_fp.glsl +++ /dev/null @@ -1,58 +0,0 @@ -uniform sampler2D u_ScreenImageMap; -uniform sampler2D u_ScreenDepthMap; - -uniform vec4 u_ViewInfo; // zfar / znear, zfar -varying vec2 var_ScreenTex; - -//float gauss[5] = float[5](0.30, 0.23, 0.097, 0.024, 0.0033); -float gauss[4] = float[4](0.40, 0.24, 0.054, 0.0044); -//float gauss[3] = float[3](0.60, 0.19, 0.0066); -#define GAUSS_SIZE 4 - -float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear) -{ - float sampleZDivW = texture2D(depthMap, tex).r; - return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); -} - -vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar) -{ - float scale = 1.0 / 256.0; - -#if defined(USE_HORIZONTAL_BLUR) - vec2 direction = vec2(1.0, 0.0) * scale; -#else // if defined(USE_VERTICAL_BLUR) - vec2 direction = vec2(0.0, 1.0) * scale; -#endif - - float depthCenter = zFar * getLinearDepth(depthMap, tex, zFarDivZNear); - vec2 centerSlope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y)); - - vec4 result = texture2D(imageMap, tex) * gauss[0]; - float total = gauss[0]; - - int i, j; - for (i = 0; i < 2; i++) - { - for (j = 1; j < GAUSS_SIZE; j++) - { - vec2 offset = direction * j; - float depthSample = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear); - float depthExpected = depthCenter + dot(centerSlope, offset); - if(abs(depthSample - depthExpected) < 5.0) - { - result += texture2D(imageMap, tex + offset) * gauss[j]; - total += gauss[j]; - } - } - - direction = -direction; - } - - return result / total; -} - -void main() -{ - gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y); -} diff --git a/code/renderergl2/glsl/depthblur_vp.glsl b/code/renderergl2/glsl/depthblur_vp.glsl deleted file mode 100644 index 9c46a79f26..0000000000 --- a/code/renderergl2/glsl/depthblur_vp.glsl +++ /dev/null @@ -1,12 +0,0 @@ -attribute vec4 attr_Position; -attribute vec4 attr_TexCoord0; - -varying vec2 var_ScreenTex; - -void main() -{ - gl_Position = attr_Position; - var_ScreenTex = attr_TexCoord0.xy; - //vec2 screenCoords = gl_Position.xy / gl_Position.w; - //var_ScreenTex = screenCoords * 0.5 + 0.5; -} diff --git a/code/renderergl2/glsl/dlight_fp.glsl b/code/renderergl2/glsl/dlight_fp.glsl deleted file mode 100644 index 8ffca5b98d..0000000000 --- a/code/renderergl2/glsl/dlight_fp.glsl +++ /dev/null @@ -1,12 +0,0 @@ -uniform sampler2D u_DiffuseMap; - -varying vec2 var_Tex1; -varying vec4 var_Color; - - -void main() -{ - vec4 color = texture2D(u_DiffuseMap, var_Tex1); - - gl_FragColor = color * var_Color; -} diff --git a/code/renderergl2/glsl/dlight_vp.glsl b/code/renderergl2/glsl/dlight_vp.glsl deleted file mode 100644 index 9566a04c26..0000000000 --- a/code/renderergl2/glsl/dlight_vp.glsl +++ /dev/null @@ -1,92 +0,0 @@ -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; -attribute vec3 attr_Normal; - -uniform vec4 u_DlightInfo; - -#if defined(USE_DEFORM_VERTEXES) -uniform int u_DeformGen; -uniform float u_DeformParams[5]; -uniform float u_Time; -#endif - -uniform vec4 u_Color; -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_Tex1; -varying vec4 var_Color; - -#if defined(USE_DEFORM_VERTEXES) -vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) -{ - if (u_DeformGen == 0) - { - return pos; - } - - float base = u_DeformParams[0]; - float amplitude = u_DeformParams[1]; - float phase = u_DeformParams[2]; - float frequency = u_DeformParams[3]; - float spread = u_DeformParams[4]; - - if (u_DeformGen == DGEN_BULGE) - { - phase *= st.x; - } - else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) - { - phase += dot(pos.xyz, vec3(spread)); - } - - float value = phase + (u_Time * frequency); - float func; - - if (u_DeformGen == DGEN_WAVE_SIN) - { - func = sin(value * 2.0 * M_PI); - } - else if (u_DeformGen == DGEN_WAVE_SQUARE) - { - func = sign(0.5 - fract(value)); - } - else if (u_DeformGen == DGEN_WAVE_TRIANGLE) - { - func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0; - } - else if (u_DeformGen == DGEN_WAVE_SAWTOOTH) - { - func = fract(value); - } - else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH) - { - func = (1.0 - fract(value)); - } - else // if (u_DeformGen == DGEN_BULGE) - { - func = sin(value); - } - - return pos + normal * (base + func * amplitude); -} -#endif - -void main() -{ - vec3 position = attr_Position; - vec3 normal = attr_Normal * 2.0 - vec3(1.0); - -#if defined(USE_DEFORM_VERTEXES) - position = DeformPosition(position, normal, attr_TexCoord0.st); -#endif - - gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - - vec3 dist = u_DlightInfo.xyz - position; - - var_Tex1 = dist.xy * u_DlightInfo.a + vec2(0.5); - float dlightmod = step(0.0, dot(dist, normal)); - dlightmod *= clamp(2.0 * (1.0 - abs(dist.z) * u_DlightInfo.a), 0.0, 1.0); - - var_Color = u_Color * dlightmod; -} diff --git a/code/renderergl2/glsl/down4x_fp.glsl b/code/renderergl2/glsl/down4x_fp.glsl deleted file mode 100644 index 0f88fb2e34..0000000000 --- a/code/renderergl2/glsl/down4x_fp.glsl +++ /dev/null @@ -1,34 +0,0 @@ -uniform sampler2D u_TextureMap; - -uniform vec2 u_InvTexRes; -varying vec2 var_TexCoords; - -void main() -{ - vec4 color; - vec2 tc; - - tc = var_TexCoords + u_InvTexRes * vec2(-1.5, -1.5); color = texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2(-0.5, -1.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 0.5, -1.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 1.5, -1.5); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2(-1.5, -0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2(-0.5, -0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 0.5, -0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 1.5, -0.5); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2(-1.5, 0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2(-0.5, 0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 0.5, 0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 1.5, 0.5); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2(-1.5, 1.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2(-0.5, 1.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 0.5, 1.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 1.5, 1.5); color += texture2D(u_TextureMap, tc); - - color *= 0.0625; - - gl_FragColor = color; -} diff --git a/code/renderergl2/glsl/down4x_vp.glsl b/code/renderergl2/glsl/down4x_vp.glsl deleted file mode 100644 index bdaa74af8e..0000000000 --- a/code/renderergl2/glsl/down4x_vp.glsl +++ /dev/null @@ -1,13 +0,0 @@ -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_TexCoords; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - var_TexCoords = attr_TexCoord0.st; -} diff --git a/code/renderergl2/glsl/fogpass_fp.glsl b/code/renderergl2/glsl/fogpass_fp.glsl deleted file mode 100644 index e2ad465ba3..0000000000 --- a/code/renderergl2/glsl/fogpass_fp.glsl +++ /dev/null @@ -1,9 +0,0 @@ -uniform vec4 u_Color; - -varying float var_Scale; - -void main() -{ - gl_FragColor = u_Color; - gl_FragColor.a = sqrt(clamp(var_Scale, 0.0, 1.0)); -} diff --git a/code/renderergl2/glsl/fogpass_vp.glsl b/code/renderergl2/glsl/fogpass_vp.glsl deleted file mode 100644 index 8f7bc72879..0000000000 --- a/code/renderergl2/glsl/fogpass_vp.glsl +++ /dev/null @@ -1,118 +0,0 @@ -attribute vec3 attr_Position; -attribute vec3 attr_Normal; - -attribute vec4 attr_TexCoord0; - -#if defined(USE_VERTEX_ANIMATION) -attribute vec3 attr_Position2; -attribute vec3 attr_Normal2; -#endif - -uniform vec4 u_FogDistance; -uniform vec4 u_FogDepth; -uniform float u_FogEyeT; - -#if defined(USE_DEFORM_VERTEXES) -uniform int u_DeformGen; -uniform float u_DeformParams[5]; -#endif - -uniform float u_Time; -uniform mat4 u_ModelViewProjectionMatrix; - -#if defined(USE_VERTEX_ANIMATION) -uniform float u_VertexLerp; -#endif - -uniform vec4 u_Color; - -varying float var_Scale; - -#if defined(USE_DEFORM_VERTEXES) -vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) -{ - if (u_DeformGen == 0) - { - return pos; - } - - float base = u_DeformParams[0]; - float amplitude = u_DeformParams[1]; - float phase = u_DeformParams[2]; - float frequency = u_DeformParams[3]; - float spread = u_DeformParams[4]; - - if (u_DeformGen == DGEN_BULGE) - { - phase *= st.x; - } - else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) - { - phase += dot(pos.xyz, vec3(spread)); - } - - float value = phase + (u_Time * frequency); - float func; - - if (u_DeformGen == DGEN_WAVE_SIN) - { - func = sin(value * 2.0 * M_PI); - } - else if (u_DeformGen == DGEN_WAVE_SQUARE) - { - func = sign(0.5 - fract(value)); - } - else if (u_DeformGen == DGEN_WAVE_TRIANGLE) - { - func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0; - } - else if (u_DeformGen == DGEN_WAVE_SAWTOOTH) - { - func = fract(value); - } - else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH) - { - func = (1.0 - fract(value)); - } - else // if (u_DeformGen == DGEN_BULGE) - { - func = sin(value); - } - - return pos + normal * (base + func * amplitude); -} -#endif - -float CalcFog(vec3 position) -{ - float s = dot(vec4(position, 1.0), u_FogDistance) * 8.0; - float t = dot(vec4(position, 1.0), u_FogDepth); - - float eyeOutside = float(u_FogEyeT < 0.0); - float fogged = float(t >= eyeOutside); - - t += 1e-6; - t *= fogged / (t - u_FogEyeT * eyeOutside); - - return s * t; -} - -void main() -{ -#if defined(USE_VERTEX_ANIMATION) - vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); - normal = normalize(normal - vec3(0.5)); -#else - vec3 position = attr_Position; - vec3 normal = attr_Normal * 2.0 - vec3(1.0); -#endif - -#if defined(USE_DEFORM_VERTEXES) - position.xyz = DeformPosition(position.xyz, normal, attr_TexCoord0.st); -#endif - - gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - - var_Scale = CalcFog(position) * u_Color.a * u_Color.a; -} diff --git a/code/renderergl2/glsl/generic_fp.glsl b/code/renderergl2/glsl/generic_fp.glsl deleted file mode 100644 index aefa33c3fa..0000000000 --- a/code/renderergl2/glsl/generic_fp.glsl +++ /dev/null @@ -1,45 +0,0 @@ -uniform sampler2D u_DiffuseMap; - -#if defined(USE_LIGHTMAP) -uniform sampler2D u_LightMap; - -uniform int u_Texture1Env; -#endif - -varying vec2 var_DiffuseTex; - -#if defined(USE_LIGHTMAP) -varying vec2 var_LightTex; -#endif - -varying vec4 var_Color; - - -void main() -{ - vec4 color = texture2D(u_DiffuseMap, var_DiffuseTex); -#if defined(USE_LIGHTMAP) - vec4 color2 = texture2D(u_LightMap, var_LightTex); - #if defined(RGBM_LIGHTMAP) - color2.rgb *= color2.a; - color2.a = 1.0; - #endif - - if (u_Texture1Env == TEXENV_MODULATE) - { - color *= color2; - } - else if (u_Texture1Env == TEXENV_ADD) - { - color += color2; - } - else if (u_Texture1Env == TEXENV_REPLACE) - { - color = color2; - } - - //color = color * (u_Texture1Env.xxxx + color2 * u_Texture1Env.z) + color2 * u_Texture1Env.y; -#endif - - gl_FragColor = color * var_Color; -} diff --git a/code/renderergl2/glsl/generic_vp.glsl b/code/renderergl2/glsl/generic_vp.glsl deleted file mode 100644 index 0e5b38b41b..0000000000 --- a/code/renderergl2/glsl/generic_vp.glsl +++ /dev/null @@ -1,247 +0,0 @@ -attribute vec3 attr_Position; -attribute vec3 attr_Normal; - -#if defined(USE_VERTEX_ANIMATION) -attribute vec3 attr_Position2; -attribute vec3 attr_Normal2; -#endif - -attribute vec4 attr_Color; -attribute vec4 attr_TexCoord0; - -#if defined(USE_LIGHTMAP) || defined(USE_TCGEN) -attribute vec4 attr_TexCoord1; -#endif - -uniform vec4 u_DiffuseTexMatrix; -uniform vec4 u_DiffuseTexOffTurb; - -#if defined(USE_TCGEN) || defined(USE_RGBAGEN) -uniform vec3 u_LocalViewOrigin; -#endif - -#if defined(USE_TCGEN) -uniform int u_TCGen0; -uniform vec3 u_TCGen0Vector0; -uniform vec3 u_TCGen0Vector1; -#endif - -#if defined(USE_FOG) -uniform vec4 u_FogDistance; -uniform vec4 u_FogDepth; -uniform float u_FogEyeT; -uniform vec4 u_FogColorMask; -#endif - -#if defined(USE_DEFORM_VERTEXES) -uniform int u_DeformGen; -uniform float u_DeformParams[5]; -uniform float u_Time; -#endif - -uniform mat4 u_ModelViewProjectionMatrix; -uniform vec4 u_BaseColor; -uniform vec4 u_VertColor; - -#if defined(USE_RGBAGEN) -uniform int u_ColorGen; -uniform int u_AlphaGen; -uniform vec3 u_AmbientLight; -uniform vec3 u_DirectedLight; -uniform vec3 u_ModelLightDir; -uniform float u_PortalRange; -#endif - -#if defined(USE_VERTEX_ANIMATION) -uniform float u_VertexLerp; -#endif - -varying vec2 var_DiffuseTex; -#if defined(USE_LIGHTMAP) -varying vec2 var_LightTex; -#endif -varying vec4 var_Color; - -#if defined(USE_DEFORM_VERTEXES) -vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) -{ - float base = u_DeformParams[0]; - float amplitude = u_DeformParams[1]; - float phase = u_DeformParams[2]; - float frequency = u_DeformParams[3]; - float spread = u_DeformParams[4]; - - if (u_DeformGen == DGEN_BULGE) - { - phase *= st.x; - } - else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) - { - phase += dot(pos.xyz, vec3(spread)); - } - - float value = phase + (u_Time * frequency); - float func; - - if (u_DeformGen == DGEN_WAVE_SIN) - { - func = sin(value * 2.0 * M_PI); - } - else if (u_DeformGen == DGEN_WAVE_SQUARE) - { - func = sign(fract(0.5 - value)); - } - else if (u_DeformGen == DGEN_WAVE_TRIANGLE) - { - func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0; - } - else if (u_DeformGen == DGEN_WAVE_SAWTOOTH) - { - func = fract(value); - } - else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH) - { - func = (1.0 - fract(value)); - } - else // if (u_DeformGen == DGEN_BULGE) - { - func = sin(value); - } - - return pos + normal * (base + func * amplitude); -} -#endif - -#if defined(USE_TCGEN) -vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 TCGenVector1) -{ - vec2 tex = attr_TexCoord0.st; - - if (TCGen == TCGEN_LIGHTMAP) - { - tex = attr_TexCoord1.st; - } - else if (TCGen == TCGEN_ENVIRONMENT_MAPPED) - { - vec3 viewer = normalize(u_LocalViewOrigin - position); - vec2 ref = reflect(viewer, normal).yz; - tex.s = ref.x * -0.5 + 0.5; - tex.t = ref.y * 0.5 + 0.5; - } - else if (TCGen == TCGEN_VECTOR) - { - tex = vec2(dot(position, TCGenVector0), dot(position, TCGenVector1)); - } - - return tex; -} -#endif - -#if defined(USE_TCMOD) -vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb) -{ - float amplitude = offTurb.z; - float phase = offTurb.w * 2.0 * M_PI; - vec2 st2; - st2.x = st.x * texMatrix.x + (st.y * texMatrix.z + offTurb.x); - st2.y = st.x * texMatrix.y + (st.y * texMatrix.w + offTurb.y); - - vec2 offsetPos = vec2(position.x + position.z, position.y); - - vec2 texOffset = sin(offsetPos * (2.0 * M_PI / 1024.0) + vec2(phase)); - - return st2 + texOffset * amplitude; -} -#endif - -#if defined(USE_RGBAGEN) -vec4 CalcColor(vec3 position, vec3 normal) -{ - vec4 color = u_VertColor * attr_Color + u_BaseColor; - - if (u_ColorGen == CGEN_LIGHTING_DIFFUSE) - { - float incoming = clamp(dot(normal, u_ModelLightDir), 0.0, 1.0); - - color.rgb = clamp(u_DirectedLight * incoming + u_AmbientLight, 0.0, 1.0); - } - - vec3 viewer = u_LocalViewOrigin - position; - - if (u_AlphaGen == AGEN_LIGHTING_SPECULAR) - { - vec3 lightDir = normalize(vec3(-960.0, 1980.0, 96.0) - position); - vec3 reflected = -reflect(lightDir, normal); - - color.a = clamp(dot(reflected, normalize(viewer)), 0.0, 1.0); - color.a *= color.a; - color.a *= color.a; - } - else if (u_AlphaGen == AGEN_PORTAL) - { - color.a = clamp(length(viewer) / u_PortalRange, 0.0, 1.0); - } - - return color; -} -#endif - -#if defined(USE_FOG) -float CalcFog(vec3 position) -{ - float s = dot(vec4(position, 1.0), u_FogDistance) * 8.0; - float t = dot(vec4(position, 1.0), u_FogDepth); - - float eyeOutside = float(u_FogEyeT < 0.0); - float fogged = float(t < eyeOutside); - - t += 1e-6; - t *= fogged / (t - u_FogEyeT * eyeOutside); - - return s * t; -} -#endif - -void main() -{ -#if defined(USE_VERTEX_ANIMATION) - vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); - normal = normalize(normal - vec3(0.5)); -#else - vec3 position = attr_Position; - vec3 normal = attr_Normal * 2.0 - vec3(1.0); -#endif - -#if defined(USE_DEFORM_VERTEXES) - position = DeformPosition(position, normal, attr_TexCoord0.st); -#endif - - gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - -#if defined(USE_TCGEN) - vec2 tex = GenTexCoords(u_TCGen0, position, normal, u_TCGen0Vector0, u_TCGen0Vector1); -#else - vec2 tex = attr_TexCoord0.st; -#endif - -#if defined(USE_TCMOD) - var_DiffuseTex = ModTexCoords(tex, position, u_DiffuseTexMatrix, u_DiffuseTexOffTurb); -#else - var_DiffuseTex = tex; -#endif - -#if defined(USE_LIGHTMAP) - var_LightTex = attr_TexCoord1.st; -#endif - -#if defined(USE_RGBAGEN) - var_Color = CalcColor(position, normal); -#else - var_Color = u_VertColor * attr_Color + u_BaseColor; -#endif - -#if defined(USE_FOG) - var_Color *= vec4(1.0) - u_FogColorMask * sqrt(clamp(CalcFog(position), 0.0, 1.0)); -#endif -} diff --git a/code/renderergl2/glsl/lightall_fp.glsl b/code/renderergl2/glsl/lightall_fp.glsl deleted file mode 100644 index b983d6fef6..0000000000 --- a/code/renderergl2/glsl/lightall_fp.glsl +++ /dev/null @@ -1,537 +0,0 @@ -uniform sampler2D u_DiffuseMap; - -#if defined(USE_LIGHTMAP) -uniform sampler2D u_LightMap; -#endif - -#if defined(USE_NORMALMAP) -uniform sampler2D u_NormalMap; -#endif - -#if defined(USE_DELUXEMAP) -uniform sampler2D u_DeluxeMap; -#endif - -#if defined(USE_SPECULARMAP) -uniform sampler2D u_SpecularMap; -#endif - -#if defined(USE_SHADOWMAP) -uniform sampler2D u_ShadowMap; -#endif - -#if defined(USE_CUBEMAP) -uniform samplerCube u_CubeMap; -#endif - -#if defined(USE_NORMALMAP) || defined(USE_DELUXEMAP) || defined(USE_SPECULARMAP) || defined(USE_CUBEMAP) -uniform vec4 u_EnableTextures; // x = normal, y = deluxe, z = specular, w = cube -#endif - -#if defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT) -uniform vec3 u_DirectedLight; -uniform vec3 u_AmbientLight; -#endif - -#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) -uniform vec3 u_PrimaryLightColor; -uniform vec3 u_PrimaryLightAmbient; -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) -uniform vec2 u_MaterialInfo; -#endif - -varying vec4 var_TexCoords; - -varying vec4 var_Color; - -#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) - #if defined(USE_VERT_TANGENT_SPACE) -varying vec4 var_Normal; -varying vec4 var_Tangent; -varying vec4 var_Bitangent; - #else -varying vec3 var_Normal; -varying vec3 var_ViewDir; - #endif -#endif - -#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) -varying vec3 var_LightColor; -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) -varying vec4 var_LightDir; -#endif - -#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) -varying vec4 var_PrimaryLightDir; -#endif - - -#define EPSILON 0.00000001 - -#if defined(USE_PARALLAXMAP) -float SampleDepth(sampler2D normalMap, vec2 t) -{ - #if defined(SWIZZLE_NORMALMAP) - return 1.0 - texture2D(normalMap, t).r; - #else - return 1.0 - texture2D(normalMap, t).a; - #endif -} - -float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap) -{ - const int linearSearchSteps = 16; - const int binarySearchSteps = 6; - - // current size of search window - float size = 1.0 / float(linearSearchSteps); - - // current depth position - float depth = 0.0; - - // best match found (starts with last position 1.0) - float bestDepth = 1.0; - - // search front to back for first point inside object - for(int i = 0; i < linearSearchSteps - 1; ++i) - { - depth += size; - - float t = SampleDepth(normalMap, dp + ds * depth); - - if(bestDepth > 0.996) // if no depth found yet - if(depth >= t) - bestDepth = depth; // store best depth - } - - depth = bestDepth; - - // recurse around first point (depth) for closest match - for(int i = 0; i < binarySearchSteps; ++i) - { - size *= 0.5; - - float t = SampleDepth(normalMap, dp + ds * depth); - - if(depth >= t) - { - bestDepth = depth; - depth -= 2.0 * size; - } - - depth += size; - } - - return bestDepth; -} -#endif - -vec3 CalcDiffuse(vec3 diffuseAlbedo, vec3 N, vec3 L, vec3 E, float NE, float NL, float shininess) -{ - #if defined(USE_OREN_NAYAR) || defined(USE_TRIACE_OREN_NAYAR) - float gamma = dot(E, L) - NE * NL; - float B = 2.22222 + 0.1 * shininess; - - #if defined(USE_OREN_NAYAR) - float A = 1.0 - 1.0 / (2.0 + 0.33 * shininess); - gamma = clamp(gamma, 0.0, 1.0); - #endif - - #if defined(USE_TRIACE_OREN_NAYAR) - float A = 1.0 - 1.0 / (2.0 + 0.65 * shininess); - - if (gamma >= 0.0) - #endif - { - B = max(B * max(NL, NE), EPSILON); - } - - return diffuseAlbedo * (A + gamma / B); - #else - return diffuseAlbedo; - #endif -} - -vec3 EnvironmentBRDF(float gloss, float NE, vec3 specular) -{ - #if 1 - // from http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - vec4 t = vec4( 1/0.96, 0.475, (0.0275 - 0.25 * 0.04)/0.96,0.25 ) * gloss; - t += vec4( 0.0, 0.0, (0.015 - 0.75 * 0.04)/0.96,0.75 ); - float a0 = t.x * min( t.y, exp2( -9.28 * NE ) ) + t.z; - float a1 = t.w; - return clamp( a0 + specular * ( a1 - a0 ), 0.0, 1.0 ); - #elif 0 - // from http://seblagarde.wordpress.com/2011/08/17/hello-world/ - return mix(specular.rgb, max(specular.rgb, vec3(gloss)), CalcFresnel(NE)); - #else - // from http://advances.realtimerendering.com/s2011/Lazarov-Physically-Based-Lighting-in-Black-Ops%20%28Siggraph%202011%20Advances%20in%20Real-Time%20Rendering%20Course%29.pptx - return mix(specular.rgb, vec3(1.0), CalcFresnel(NE) / (4.0 - 3.0 * gloss)); - #endif -} - -float CalcBlinn(float NH, float shininess) -{ -#if defined(USE_BLINN) || defined(USE_BLINN_FRESNEL) - // Normalized Blinn-Phong - float norm = shininess * 0.125 + 1.0; -#elif defined(USE_MCAULEY) - // Cook-Torrance as done by Stephen McAuley - // http://blog.selfshadow.com/publications/s2012-shading-course/mcauley/s2012_pbs_farcry3_notes_v2.pdf - float norm = shininess * 0.25 + 0.125; -#elif defined(USE_GOTANDA) - // Neumann-Neumann as done by Yoshiharu Gotanda - // http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf - float norm = shininess * 0.124858 + 0.269182; -#elif defined(USE_LAZAROV) - // Cook-Torrance as done by Dimitar Lazarov - // http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - float norm = shininess * 0.125 + 0.25; -#else - float norm = 1.0; -#endif - -#if 0 - // from http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/ - float a = shininess + 0.775; - return norm * exp(a * NH - a); -#else - return norm * pow(NH, shininess); -#endif -} - -float CalcGGX(float NH, float gloss) -{ - // from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf - float a_sq = exp2(gloss * -13.0 + 1.0); - float d = ((NH * NH) * (a_sq - 1.0) + 1.0); - return a_sq / (d * d); -} - -float CalcFresnel(float EH) -{ -#if 1 - // From http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - // not accurate, but fast - return exp2(-10.0 * EH); -#elif 0 - // From http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/ - return exp2((-5.55473 * EH - 6.98316) * EH); -#elif 0 - float blend = 1.0 - EH; - float blend2 = blend * blend; - blend *= blend2 * blend2; - - return blend; -#else - return pow(1.0 - EH, 5.0); -#endif -} - -float CalcVisibility(float NH, float NL, float NE, float EH, float gloss) -{ -#if defined(USE_GOTANDA) - // Neumann-Neumann as done by Yoshiharu Gotanda - // http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf - return 1.0 / max(max(NL, NE), EPSILON); -#elif defined(USE_LAZAROV) - // Cook-Torrance as done by Dimitar Lazarov - // http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - float k = min(1.0, gloss + 0.545); - return 1.0 / (k * (EH * EH - 1.0) + 1.0); -#elif defined(USE_GGX) - float roughness = exp2(gloss * -6.5); - - // Modified from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf - // NL, NE in numerator factored out from cook-torrance - float k = roughness + 1.0; - k *= k * 0.125; - - float k2 = 1.0 - k; - - float invGeo1 = NL * k2 + k; - float invGeo2 = NE * k2 + k; - - return 1.0 / (invGeo1 * invGeo2); -#else - return 1.0; -#endif -} - - -vec3 CalcSpecular(vec3 specular, float NH, float NL, float NE, float EH, float gloss, float shininess) -{ -#if defined(USE_GGX) - float distrib = CalcGGX(NH, gloss); -#else - float distrib = CalcBlinn(NH, shininess); -#endif - -#if defined(USE_BLINN) - vec3 fSpecular = specular; -#else - vec3 fSpecular = mix(specular, vec3(1.0), CalcFresnel(EH)); -#endif - - float vis = CalcVisibility(NH, NL, NE, EH, gloss); - - return fSpecular * (distrib * vis); -} - - -float CalcLightAttenuation(float point, float normDist) -{ - // zero light at 1.0, approximating q3 style - // also don't attenuate directional light - float attenuation = (0.5 * normDist - 1.5) * point + 1.0; - - // clamp attenuation - #if defined(NO_LIGHT_CLAMP) - attenuation = max(attenuation, 0.0); - #else - attenuation = clamp(attenuation, 0.0, 1.0); - #endif - - return attenuation; -} - -// from http://www.thetenthplanet.de/archives/1180 -mat3 cotangent_frame( vec3 N, vec3 p, vec2 uv ) -{ - // get edge vectors of the pixel triangle - vec3 dp1 = dFdx( p ); - vec3 dp2 = dFdy( p ); - vec2 duv1 = dFdx( uv ); - vec2 duv2 = dFdy( uv ); - - // solve the linear system - vec3 dp2perp = cross( dp2, N ); - vec3 dp1perp = cross( N, dp1 ); - vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; - vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; - - // construct a scale-invariant frame - float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) ); - return mat3( T * invmax, B * invmax, N ); -} - -void main() -{ - vec3 L, N, E, H; - float NL, NH, NE, EH; - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - #if defined(USE_VERT_TANGENT_SPACE) - mat3 tangentToWorld = mat3(var_Tangent.xyz, var_Bitangent.xyz, var_Normal.xyz); - E = vec3(var_Normal.w, var_Tangent.w, var_Bitangent.w); - #else - mat3 tangentToWorld = cotangent_frame(var_Normal, -var_ViewDir, var_TexCoords.xy); - E = var_ViewDir; - #endif - - E = normalize(E); - - L = var_LightDir.xyz; - #if defined(USE_DELUXEMAP) - L += (texture2D(u_DeluxeMap, var_TexCoords.zw).xyz - vec3(0.5)) * u_EnableTextures.y; - #endif - float sqrLightDist = dot(L, L); -#endif - -#if defined(USE_LIGHTMAP) - vec4 lightSample = texture2D(u_LightMap, var_TexCoords.zw); - vec3 lightColor = lightSample.rgb; - #if defined(RGBM_LIGHTMAP) - lightColor *= lightSample.a; - #endif -#elif defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT) - vec3 lightColor = u_DirectedLight * CalcLightAttenuation(float(var_LightDir.w > 0.0), var_LightDir.w / sqrLightDist); - vec3 ambientColor = u_AmbientLight; -#elif defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) - vec3 lightColor = var_LightColor; -#endif - - vec2 texCoords = var_TexCoords.xy; - -#if defined(USE_PARALLAXMAP) - vec3 offsetDir = normalize(E * tangentToWorld); - - offsetDir.xy *= -0.05 / offsetDir.z; - - texCoords += offsetDir.xy * RayIntersectDisplaceMap(texCoords, offsetDir.xy, u_NormalMap); -#endif - - vec4 diffuse = texture2D(u_DiffuseMap, texCoords); -#if defined(USE_GAMMA2_TEXTURES) - diffuse.rgb *= diffuse.rgb; -#endif - - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - #if defined(USE_NORMALMAP) - #if defined(SWIZZLE_NORMALMAP) - N.xy = texture2D(u_NormalMap, texCoords).ag - vec2(0.5); - #else - N.xy = texture2D(u_NormalMap, texCoords).rg - vec2(0.5); - #endif - N.xy *= u_EnableTextures.x; - N.z = sqrt((0.25 - N.x * N.x) - N.y * N.y); - N = tangentToWorld * N; - #else - N = var_Normal.xyz; - #endif - - N = normalize(N); - L /= sqrt(sqrLightDist); - - #if defined(USE_SHADOWMAP) - vec2 shadowTex = gl_FragCoord.xy * r_FBufScale; - float shadowValue = texture2D(u_ShadowMap, shadowTex).r; - - // surfaces not facing the light are always shadowed - shadowValue *= float(dot(var_Normal.xyz, var_PrimaryLightDir.xyz) > 0.0); - - #if defined(SHADOWMAP_MODULATE) - //vec3 shadowColor = min(u_PrimaryLightAmbient, lightColor); - vec3 shadowColor = u_PrimaryLightAmbient * lightColor; - - #if 0 - // Only shadow when the world light is parallel to the primary light - shadowValue = 1.0 + (shadowValue - 1.0) * clamp(dot(L, var_PrimaryLightDir.xyz), 0.0, 1.0); - #endif - lightColor = mix(shadowColor, lightColor, shadowValue); - #endif - #endif - - #if defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX) - vec3 ambientColor = lightColor; - float surfNL = clamp(dot(var_Normal.xyz, L), 0.0, 1.0); - - // Scale the incoming light to compensate for the baked-in light angle - // attenuation. - lightColor /= max(surfNL, 0.25); - - // Recover any unused light as ambient, in case attenuation is over 4x or - // light is below the surface - ambientColor -= lightColor * surfNL; - #endif - - vec3 reflectance; - - NL = clamp(dot(N, L), 0.0, 1.0); - NE = clamp(dot(N, E), 0.0, 1.0); - - vec4 specular = vec4(1.0); - #if defined(USE_SPECULARMAP) - specular += texture2D(u_SpecularMap, texCoords) * u_EnableTextures.z - u_EnableTextures.zzzz; - #if defined(USE_GAMMA2_TEXTURES) - specular.rgb *= specular.rgb; - #endif - #endif - - specular *= u_MaterialInfo.xxxy; - - float gloss = specular.a; - float shininess = exp2(gloss * 13.0); - - #if defined(SPECULAR_IS_METALLIC) - // diffuse is actually base color, and red of specular is metallicness - float metallic = specular.r; - - specular.rgb = (0.96 * metallic) * diffuse.rgb + vec3(0.04); - diffuse.rgb *= 1.0 - metallic; - #else - // adjust diffuse by specular reflectance, to maintain energy conservation - diffuse.rgb *= vec3(1.0) - specular.rgb; - #endif - - reflectance = CalcDiffuse(diffuse.rgb, N, L, E, NE, NL, shininess); - - #if defined(r_deluxeSpecular) || defined(USE_LIGHT_VECTOR) - float adjGloss = gloss; - float adjShininess = shininess; - - #if !defined(USE_LIGHT_VECTOR) - adjGloss *= r_deluxeSpecular; - adjShininess = exp2(adjGloss * 13.0); - #endif - - H = normalize(L + E); - - EH = clamp(dot(E, H), 0.0, 1.0); - NH = clamp(dot(N, H), 0.0, 1.0); - - #if !defined(USE_LIGHT_VECTOR) - reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjGloss, adjShininess) * r_deluxeSpecular; - #else - reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjGloss, adjShininess); - #endif - #endif - - gl_FragColor.rgb = lightColor * reflectance * NL; - gl_FragColor.rgb += ambientColor * (diffuse.rgb + specular.rgb); - - #if defined(USE_CUBEMAP) - reflectance = EnvironmentBRDF(gloss, NE, specular.rgb); - - vec3 R = reflect(E, N); - - vec3 cubeLightColor = textureCubeLod(u_CubeMap, R, 7.0 - gloss * 7.0).rgb * u_EnableTextures.w; - - #if defined(USE_LIGHTMAP) - cubeLightColor *= lightSample.rgb; - #elif defined (USE_LIGHT_VERTEX) - cubeLightColor *= var_LightColor; - #else - cubeLightColor *= lightColor * NL + ambientColor; - #endif - - //gl_FragColor.rgb += diffuse.rgb * textureCubeLod(u_CubeMap, N, 7.0).rgb * u_EnableTextures.w; - gl_FragColor.rgb += cubeLightColor * reflectance; - #endif - - #if defined(USE_PRIMARY_LIGHT) - vec3 L2, H2; - float NL2, EH2, NH2; - - L2 = var_PrimaryLightDir.xyz; - - // enable when point lights are supported as primary lights - //sqrLightDist = dot(L2, L2); - //L2 /= sqrt(sqrLightDist); - - NL2 = clamp(dot(N, L2), 0.0, 1.0); - - H2 = normalize(L2 + E); - EH2 = clamp(dot(E, H2), 0.0, 1.0); - NH2 = clamp(dot(N, H2), 0.0, 1.0); - - reflectance = CalcDiffuse(diffuse.rgb, N, L2, E, NE, NL2, shininess); - reflectance += CalcSpecular(specular.rgb, NH2, NL2, NE, EH2, gloss, shininess); - - lightColor = u_PrimaryLightColor; - - // enable when point lights are supported as primary lights - //lightColor *= CalcLightAttenuation(float(u_PrimaryLightDir.w > 0.0), u_PrimaryLightDir.w / sqrLightDist); - - #if defined(USE_SHADOWMAP) - lightColor *= shadowValue; - #endif - - gl_FragColor.rgb += lightColor * reflectance * NL2; - #endif - - gl_FragColor.a = diffuse.a; -#else - gl_FragColor = diffuse; - #if defined(USE_LIGHTMAP) - gl_FragColor.rgb *= lightColor; - #endif -#endif - - gl_FragColor *= var_Color; -} diff --git a/code/renderergl2/glsl/lightall_vp.glsl b/code/renderergl2/glsl/lightall_vp.glsl deleted file mode 100644 index 2e1c899cae..0000000000 --- a/code/renderergl2/glsl/lightall_vp.glsl +++ /dev/null @@ -1,260 +0,0 @@ -attribute vec4 attr_TexCoord0; -#if defined(USE_LIGHTMAP) || defined(USE_TCGEN) -attribute vec4 attr_TexCoord1; -#endif -attribute vec4 attr_Color; - -attribute vec3 attr_Position; -attribute vec3 attr_Normal; -#if defined(USE_VERT_TANGENT_SPACE) -attribute vec4 attr_Tangent; -#endif - -#if defined(USE_VERTEX_ANIMATION) -attribute vec3 attr_Position2; -attribute vec3 attr_Normal2; - #if defined(USE_VERT_TANGENT_SPACE) -attribute vec4 attr_Tangent2; - #endif -#endif - -#if defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR) -attribute vec3 attr_LightDirection; -#endif - -#if defined(USE_DELUXEMAP) -uniform vec4 u_EnableTextures; // x = normal, y = deluxe, z = specular, w = cube -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) -uniform vec3 u_ViewOrigin; -#endif - -#if defined(USE_TCGEN) -uniform int u_TCGen0; -uniform vec3 u_TCGen0Vector0; -uniform vec3 u_TCGen0Vector1; -uniform vec3 u_LocalViewOrigin; -#endif - -#if defined(USE_TCMOD) -uniform vec4 u_DiffuseTexMatrix; -uniform vec4 u_DiffuseTexOffTurb; -#endif - -uniform mat4 u_ModelViewProjectionMatrix; -uniform vec4 u_BaseColor; -uniform vec4 u_VertColor; - -#if defined(USE_MODELMATRIX) -uniform mat4 u_ModelMatrix; -#endif - -#if defined(USE_VERTEX_ANIMATION) -uniform float u_VertexLerp; -#endif - -#if defined(USE_LIGHT_VECTOR) -uniform vec4 u_LightOrigin; -uniform float u_LightRadius; - #if defined(USE_FAST_LIGHT) -uniform vec3 u_DirectedLight; -uniform vec3 u_AmbientLight; - #endif -#endif - -#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) -uniform vec4 u_PrimaryLightOrigin; -uniform float u_PrimaryLightRadius; -#endif - -varying vec4 var_TexCoords; - -varying vec4 var_Color; - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - #if defined(USE_VERT_TANGENT_SPACE) -varying vec4 var_Normal; -varying vec4 var_Tangent; -varying vec4 var_Bitangent; - #else -varying vec3 var_Normal; -varying vec3 var_ViewDir; - #endif -#endif - -#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) -varying vec3 var_LightColor; -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) -varying vec4 var_LightDir; -#endif - -#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) -varying vec4 var_PrimaryLightDir; -#endif - -#if defined(USE_TCGEN) -vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 TCGenVector1) -{ - vec2 tex = attr_TexCoord0.st; - - if (TCGen == TCGEN_LIGHTMAP) - { - tex = attr_TexCoord1.st; - } - else if (TCGen == TCGEN_ENVIRONMENT_MAPPED) - { - vec3 viewer = normalize(u_LocalViewOrigin - position); - vec2 ref = reflect(viewer, normal).yz; - tex.s = ref.x * -0.5 + 0.5; - tex.t = ref.y * 0.5 + 0.5; - } - else if (TCGen == TCGEN_VECTOR) - { - tex = vec2(dot(position, TCGenVector0), dot(position, TCGenVector1)); - } - - return tex; -} -#endif - -#if defined(USE_TCMOD) -vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb) -{ - float amplitude = offTurb.z; - float phase = offTurb.w * 2.0 * M_PI; - vec2 st2; - st2.x = st.x * texMatrix.x + (st.y * texMatrix.z + offTurb.x); - st2.y = st.x * texMatrix.y + (st.y * texMatrix.w + offTurb.y); - - vec2 offsetPos = vec2(position.x + position.z, position.y); - - vec2 texOffset = sin(offsetPos * (2.0 * M_PI / 1024.0) + vec2(phase)); - - return st2 + texOffset * amplitude; -} -#endif - - -float CalcLightAttenuation(float point, float normDist) -{ - // zero light at 1.0, approximating q3 style - // also don't attenuate directional light - float attenuation = (0.5 * normDist - 1.5) * point + 1.0; - - // clamp attenuation - #if defined(NO_LIGHT_CLAMP) - attenuation = max(attenuation, 0.0); - #else - attenuation = clamp(attenuation, 0.0, 1.0); - #endif - - return attenuation; -} - - -void main() -{ -#if defined(USE_VERTEX_ANIMATION) - vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); - #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 tangent = mix(attr_Tangent.xyz, attr_Tangent2.xyz, u_VertexLerp); - #endif -#else - vec3 position = attr_Position; - vec3 normal = attr_Normal; - #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 tangent = attr_Tangent.xyz; - #endif -#endif - - normal = normal * 2.0 - vec3(1.0); -#if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - tangent = tangent * 2.0 - vec3(1.0); -#endif - -#if defined(USE_TCGEN) - vec2 texCoords = GenTexCoords(u_TCGen0, position, normal, u_TCGen0Vector0, u_TCGen0Vector1); -#else - vec2 texCoords = attr_TexCoord0.st; -#endif - -#if defined(USE_TCMOD) - var_TexCoords.xy = ModTexCoords(texCoords, position, u_DiffuseTexMatrix, u_DiffuseTexOffTurb); -#else - var_TexCoords.xy = texCoords; -#endif - - gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - -#if defined(USE_MODELMATRIX) - position = (u_ModelMatrix * vec4(position, 1.0)).xyz; - normal = (u_ModelMatrix * vec4(normal, 0.0)).xyz; - #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - tangent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz; - #endif -#endif - -#if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 bitangent = cross(normal, tangent) * (attr_Tangent.w * 2.0 - 1.0); -#endif - -#if defined(USE_LIGHT_VECTOR) - vec3 L = u_LightOrigin.xyz - (position * u_LightOrigin.w); -#elif defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 L = attr_LightDirection * 2.0 - vec3(1.0); - #if defined(USE_MODELMATRIX) - L = (u_ModelMatrix * vec4(L, 0.0)).xyz; - #endif -#endif - -#if defined(USE_LIGHTMAP) - var_TexCoords.zw = attr_TexCoord1.st; -#endif - - var_Color = u_VertColor * attr_Color + u_BaseColor; -#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) - var_LightColor = var_Color.rgb; - var_Color.rgb = vec3(1.0); -#endif - -#if defined(USE_LIGHT_VECTOR) && defined(USE_FAST_LIGHT) - float sqrLightDist = dot(L, L); - float attenuation = CalcLightAttenuation(u_LightOrigin.w, u_LightRadius * u_LightRadius / sqrLightDist); - float NL = clamp(dot(normalize(normal), L) / sqrt(sqrLightDist), 0.0, 1.0); - - var_Color.rgb *= u_DirectedLight * (attenuation * NL) + u_AmbientLight; -#endif - -#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) - var_PrimaryLightDir.xyz = u_PrimaryLightOrigin.xyz - (position * u_PrimaryLightOrigin.w); - var_PrimaryLightDir.w = u_PrimaryLightRadius * u_PrimaryLightRadius; -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - #if defined(USE_LIGHT_VECTOR) - var_LightDir = vec4(L, u_LightRadius * u_LightRadius); - #else - var_LightDir = vec4(L, 0.0); - #endif - #if defined(USE_DELUXEMAP) - var_LightDir -= u_EnableTextures.y * var_LightDir; - #endif -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 viewDir = u_ViewOrigin - position; - #if defined(USE_VERT_TANGENT_SPACE) - // store view direction in tangent space to save on varyings - var_Normal = vec4(normal, viewDir.x); - var_Tangent = vec4(tangent, viewDir.y); - var_Bitangent = vec4(bitangent, viewDir.z); - #else - var_Normal = normal; - var_ViewDir = viewDir; - #endif -#endif -} diff --git a/code/renderergl2/glsl/pshadow_fp.glsl b/code/renderergl2/glsl/pshadow_fp.glsl deleted file mode 100644 index b152971af6..0000000000 --- a/code/renderergl2/glsl/pshadow_fp.glsl +++ /dev/null @@ -1,98 +0,0 @@ -uniform sampler2D u_ShadowMap; - -uniform vec3 u_LightForward; -uniform vec3 u_LightUp; -uniform vec3 u_LightRight; -uniform vec4 u_LightOrigin; -uniform float u_LightRadius; -varying vec3 var_Position; -varying vec3 var_Normal; - -float sampleDistMap(sampler2D texMap, vec2 uv, float scale) -{ - vec3 distv = texture2D(texMap, uv).xyz; - return dot(distv, vec3(1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)) * scale; -} - -void main() -{ - vec3 lightToPos = var_Position - u_LightOrigin.xyz; - vec2 st = vec2(-dot(u_LightRight, lightToPos), dot(u_LightUp, lightToPos)); - - float fade = length(st); - -#if defined(USE_DISCARD) - if (fade >= 1.0) - { - discard; - } -#endif - - fade = clamp(8.0 - fade * 8.0, 0.0, 1.0); - - st = st * 0.5 + vec2(0.5); - -#if defined(USE_SOLID_PSHADOWS) - float intensity = max(sign(u_LightRadius - length(lightToPos)), 0.0); -#else - float intensity = clamp((1.0 - dot(lightToPos, lightToPos) / (u_LightRadius * u_LightRadius)) * 2.0, 0.0, 1.0); -#endif - - float lightDist = length(lightToPos); - float dist; - -#if defined(USE_DISCARD) - if (dot(u_LightForward, lightToPos) <= 0.0) - { - discard; - } - - if (dot(var_Normal, lightToPos) > 0.0) - { - discard; - } -#else - intensity *= max(sign(dot(u_LightForward, lightToPos)), 0.0); - intensity *= max(sign(-dot(var_Normal, lightToPos)), 0.0); -#endif - - intensity *= fade; -#if defined(USE_PCF) - float part; - - dist = sampleDistMap(u_ShadowMap, st + vec2(-1.0/512.0, -1.0/512.0), u_LightRadius); - part = max(sign(lightDist - dist), 0.0); - - dist = sampleDistMap(u_ShadowMap, st + vec2( 1.0/512.0, -1.0/512.0), u_LightRadius); - part += max(sign(lightDist - dist), 0.0); - - dist = sampleDistMap(u_ShadowMap, st + vec2(-1.0/512.0, 1.0/512.0), u_LightRadius); - part += max(sign(lightDist - dist), 0.0); - - dist = sampleDistMap(u_ShadowMap, st + vec2( 1.0/512.0, 1.0/512.0), u_LightRadius); - part += max(sign(lightDist - dist), 0.0); - - #if defined(USE_DISCARD) - if (part <= 0.0) - { - discard; - } - #endif - - intensity *= part * 0.25; -#else - dist = sampleDistMap(u_ShadowMap, st, u_LightRadius); - - #if defined(USE_DISCARD) - if (lightDist - dist <= 0.0) - { - discard; - } - #endif - - intensity *= max(sign(lightDist - dist), 0.0); -#endif - - gl_FragColor.rgb = vec3(0); - gl_FragColor.a = clamp(intensity, 0.0, 0.75); -} diff --git a/code/renderergl2/glsl/pshadow_vp.glsl b/code/renderergl2/glsl/pshadow_vp.glsl deleted file mode 100644 index 0f9940cd4e..0000000000 --- a/code/renderergl2/glsl/pshadow_vp.glsl +++ /dev/null @@ -1,15 +0,0 @@ -attribute vec3 attr_Position; -attribute vec3 attr_Normal; - -uniform mat4 u_ModelViewProjectionMatrix; -varying vec3 var_Position; -varying vec3 var_Normal; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - - var_Position = attr_Position; - var_Normal = attr_Normal * 2.0 - vec3(1.0); -} diff --git a/code/renderergl2/glsl/shadowfill_fp.glsl b/code/renderergl2/glsl/shadowfill_fp.glsl deleted file mode 100644 index 150f3d1229..0000000000 --- a/code/renderergl2/glsl/shadowfill_fp.glsl +++ /dev/null @@ -1,41 +0,0 @@ -uniform vec4 u_LightOrigin; -uniform float u_LightRadius; - -varying vec3 var_Position; - -void main() -{ -#if defined(USE_DEPTH) - float depth = length(u_LightOrigin.xyz - var_Position) / u_LightRadius; - #if 0 - // 32 bit precision - const vec4 bitSh = vec4( 256 * 256 * 256, 256 * 256, 256, 1); - const vec4 bitMsk = vec4( 0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); - - vec4 comp; - comp = depth * bitSh; - comp.xyz = fract(comp.xyz); - comp -= comp.xxyz * bitMsk; - gl_FragColor = comp; - #endif - - #if 1 - // 24 bit precision - const vec3 bitSh = vec3( 256 * 256, 256, 1); - const vec3 bitMsk = vec3( 0, 1.0 / 256.0, 1.0 / 256.0); - - vec3 comp; - comp = depth * bitSh; - comp.xy = fract(comp.xy); - comp -= comp.xxy * bitMsk; - gl_FragColor = vec4(comp, 1.0); - #endif - - #if 0 - // 8 bit precision - gl_FragColor = vec4(depth, depth, depth, 1); - #endif -#else - gl_FragColor = vec4(0, 0, 0, 1); -#endif -} diff --git a/code/renderergl2/glsl/shadowfill_vp.glsl b/code/renderergl2/glsl/shadowfill_vp.glsl deleted file mode 100644 index 7a5cc571a1..0000000000 --- a/code/renderergl2/glsl/shadowfill_vp.glsl +++ /dev/null @@ -1,90 +0,0 @@ -attribute vec3 attr_Position; -attribute vec3 attr_Normal; -attribute vec4 attr_TexCoord0; - -//#if defined(USE_VERTEX_ANIMATION) -attribute vec3 attr_Position2; -attribute vec3 attr_Normal2; -//#endif - -//#if defined(USE_DEFORM_VERTEXES) -uniform int u_DeformGen; -uniform float u_DeformParams[5]; -//#endif - -uniform float u_Time; -uniform mat4 u_ModelViewProjectionMatrix; - -uniform mat4 u_ModelMatrix; - -//#if defined(USE_VERTEX_ANIMATION) -uniform float u_VertexLerp; -//#endif - -varying vec3 var_Position; - -vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) -{ - if (u_DeformGen == 0) - { - return pos; - } - - float base = u_DeformParams[0]; - float amplitude = u_DeformParams[1]; - float phase = u_DeformParams[2]; - float frequency = u_DeformParams[3]; - float spread = u_DeformParams[4]; - - if (u_DeformGen == DGEN_BULGE) - { - phase *= st.x; - } - else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) - { - phase += dot(pos.xyz, vec3(spread)); - } - - float value = phase + (u_Time * frequency); - float func; - - if (u_DeformGen == DGEN_WAVE_SIN) - { - func = sin(value * 2.0 * M_PI); - } - else if (u_DeformGen == DGEN_WAVE_SQUARE) - { - func = sign(0.5 - fract(value)); - } - else if (u_DeformGen == DGEN_WAVE_TRIANGLE) - { - func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0; - } - else if (u_DeformGen == DGEN_WAVE_SAWTOOTH) - { - func = fract(value); - } - else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH) - { - func = (1.0 - fract(value)); - } - else // if (u_DeformGen == DGEN_BULGE) - { - func = sin(value); - } - - return pos + normal * (base + func * amplitude); -} - -void main() -{ - vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); - normal = normalize(normal - vec3(0.5)); - - position = DeformPosition(position, normal, attr_TexCoord0.st); - - gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - - var_Position = (u_ModelMatrix * vec4(position, 1.0)).xyz; -} diff --git a/code/renderergl2/glsl/shadowmask_fp.glsl b/code/renderergl2/glsl/shadowmask_fp.glsl deleted file mode 100644 index 4bac5ccdd8..0000000000 --- a/code/renderergl2/glsl/shadowmask_fp.glsl +++ /dev/null @@ -1,127 +0,0 @@ -uniform sampler2D u_ScreenDepthMap; - -uniform sampler2D u_ShadowMap; -#if defined(USE_SHADOW_CASCADE) -uniform sampler2D u_ShadowMap2; -uniform sampler2D u_ShadowMap3; -#endif - -uniform mat4 u_ShadowMvp; -#if defined(USE_SHADOW_CASCADE) -uniform mat4 u_ShadowMvp2; -uniform mat4 u_ShadowMvp3; -#endif - -uniform vec3 u_ViewOrigin; -uniform vec4 u_ViewInfo; // zfar / znear, zfar - -varying vec2 var_DepthTex; -varying vec3 var_ViewDir; - -// Input: It uses texture coords as the random number seed. -// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive. -// Author: Michael Pohoreski -// Copyright: Copyleft 2012 :-) -// Source: http://stackoverflow.com/questions/5149544/can-i-generate-a-random-number-inside-a-pixel-shader - -float random( const vec2 p ) -{ - // We need irrationals for pseudo randomness. - // Most (all?) known transcendental numbers will (generally) work. - const vec2 r = vec2( - 23.1406926327792690, // e^pi (Gelfond's constant) - 2.6651441426902251); // 2^sqrt(2) (Gelfond-Schneider constant) - //return fract( cos( mod( 123456789., 1e-7 + 256. * dot(p,r) ) ) ); - return mod( 123456789., 1e-7 + 256. * dot(p,r) ); -} - -float PCF(const sampler2D shadowmap, const vec2 st, const float dist) -{ - float mult; - float scale = 2.0 / r_shadowMapSize; - -#if defined(USE_SHADOW_FILTER) - float r = random(var_DepthTex.xy); - float sinr = sin(r) * scale; - float cosr = cos(r) * scale; - mat2 rmat = mat2(cosr, sinr, -sinr, cosr); - - mult = step(dist, texture2D(shadowmap, st + rmat * vec2(-0.7055767, 0.196515)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.3524343, -0.7791386)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.2391056, 0.9189604)).r); - #if defined(USE_SHADOW_FILTER2) - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(-0.07580382, -0.09224417)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.5784913, -0.002528916)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.192888, 0.4064181)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(-0.6335801, -0.5247476)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(-0.5579782, 0.7491854)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.7320465, 0.6317794)).r); - - mult *= 0.11111; - #else - mult *= 0.33333; - #endif -#else - mult = step(dist, texture2D(shadowmap, st).r); -#endif - - return mult; -} - -float getLinearDepth(sampler2D depthMap, vec2 tex, float zFarDivZNear) -{ - float sampleZDivW = texture2D(depthMap, tex).r; - return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); -} - -void main() -{ - float result; - - float depth = getLinearDepth(u_ScreenDepthMap, var_DepthTex, u_ViewInfo.x); - float sampleZ = u_ViewInfo.y * depth; - - vec4 biasPos = vec4(u_ViewOrigin + var_ViewDir * depth * 0.99, 1.0); - - vec4 shadowpos = u_ShadowMvp * biasPos; - -#if defined(USE_SHADOW_CASCADE) - const float fadeTo = 1.0; - result = fadeTo; -#else - result = 0.0; -#endif - - if (all(lessThanEqual(abs(shadowpos.xyz), vec3(abs(shadowpos.w))))) - { - shadowpos.xyz = shadowpos.xyz / shadowpos.w * 0.5 + 0.5; - result = PCF(u_ShadowMap, shadowpos.xy, shadowpos.z); - } -#if defined(USE_SHADOW_CASCADE) - else - { - shadowpos = u_ShadowMvp2 * biasPos; - - if (all(lessThanEqual(abs(shadowpos.xyz), vec3(abs(shadowpos.w))))) - { - shadowpos.xyz = shadowpos.xyz / shadowpos.w * 0.5 + 0.5; - result = PCF(u_ShadowMap2, shadowpos.xy, shadowpos.z); - } - else - { - shadowpos = u_ShadowMvp3 * biasPos; - - if (all(lessThanEqual(abs(shadowpos.xyz), vec3(abs(shadowpos.w))))) - { - shadowpos.xyz = shadowpos.xyz / shadowpos.w * 0.5 + 0.5; - result = PCF(u_ShadowMap3, shadowpos.xy, shadowpos.z); - - float fade = clamp(sampleZ / r_shadowCascadeZFar * 10.0 - 9.0, 0.0, 1.0); - result = mix(result, fadeTo, fade); - } - } - } -#endif - - gl_FragColor = vec4(vec3(result), 1.0); -} diff --git a/code/renderergl2/glsl/shadowmask_vp.glsl b/code/renderergl2/glsl/shadowmask_vp.glsl deleted file mode 100644 index 13166a2400..0000000000 --- a/code/renderergl2/glsl/shadowmask_vp.glsl +++ /dev/null @@ -1,18 +0,0 @@ -attribute vec4 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform vec3 u_ViewForward; -uniform vec3 u_ViewLeft; -uniform vec3 u_ViewUp; -uniform vec4 u_ViewInfo; // zfar / znear - -varying vec2 var_DepthTex; -varying vec3 var_ViewDir; - -void main() -{ - gl_Position = attr_Position; - vec2 screenCoords = gl_Position.xy / gl_Position.w; - var_DepthTex = attr_TexCoord0.xy; - var_ViewDir = u_ViewForward + u_ViewLeft * -screenCoords.x + u_ViewUp * screenCoords.y; -} diff --git a/code/renderergl2/glsl/ssao_fp.glsl b/code/renderergl2/glsl/ssao_fp.glsl deleted file mode 100644 index 6263284c56..0000000000 --- a/code/renderergl2/glsl/ssao_fp.glsl +++ /dev/null @@ -1,86 +0,0 @@ -uniform sampler2D u_ScreenDepthMap; - -uniform vec4 u_ViewInfo; // zfar / znear, zfar - -varying vec2 var_ScreenTex; - -vec2 poissonDisc[9] = vec2[9]( -vec2(-0.7055767, 0.196515), vec2(0.3524343, -0.7791386), -vec2(0.2391056, 0.9189604), vec2(-0.07580382, -0.09224417), -vec2(0.5784913, -0.002528916), vec2(0.192888, 0.4064181), -vec2(-0.6335801, -0.5247476), vec2(-0.5579782, 0.7491854), -vec2(0.7320465, 0.6317794) -); - -// Input: It uses texture coords as the random number seed. -// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive. -// Author: Michael Pohoreski -// Copyright: Copyleft 2012 :-) -// Source: http://stackoverflow.com/questions/5149544/can-i-generate-a-random-number-inside-a-pixel-shader - -float random( const vec2 p ) -{ - // We need irrationals for pseudo randomness. - // Most (all?) known transcendental numbers will (generally) work. - const vec2 r = vec2( - 23.1406926327792690, // e^pi (Gelfond's constant) - 2.6651441426902251); // 2^sqrt(2) (Gelfond-Schneider constant) - //return fract( cos( mod( 123456789., 1e-7 + 256. * dot(p,r) ) ) ); - return mod( 123456789., 1e-7 + 256. * dot(p,r) ); -} - -mat2 randomRotation( const vec2 p ) -{ - float r = random(p); - float sinr = sin(r); - float cosr = cos(r); - return mat2(cosr, sinr, -sinr, cosr); -} - -float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear) -{ - float sampleZDivW = texture2D(depthMap, tex).r; - return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); -} - -float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar) -{ - float result = 0; - - float sampleZ = zFar * getLinearDepth(depthMap, tex, zFarDivZNear); - - vec2 expectedSlope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y)); - - if (length(expectedSlope) > 5000.0) - return 1.0; - - vec2 offsetScale = vec2(3.0 / sampleZ); - - mat2 rmat = randomRotation(tex); - - int i; - for (i = 0; i < 3; i++) - { - vec2 offset = rmat * poissonDisc[i] * offsetScale; - float sampleZ2 = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear); - - if (abs(sampleZ - sampleZ2) > 20.0) - result += 1.0; - else - { - float expectedZ = sampleZ + dot(expectedSlope, offset); - result += step(expectedZ - 1.0, sampleZ2); - } - } - - result *= 0.33333; - - return result; -} - -void main() -{ - float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y); - - gl_FragColor = vec4(vec3(result), 1.0); -} diff --git a/code/renderergl2/glsl/ssao_vp.glsl b/code/renderergl2/glsl/ssao_vp.glsl deleted file mode 100644 index 9c46a79f26..0000000000 --- a/code/renderergl2/glsl/ssao_vp.glsl +++ /dev/null @@ -1,12 +0,0 @@ -attribute vec4 attr_Position; -attribute vec4 attr_TexCoord0; - -varying vec2 var_ScreenTex; - -void main() -{ - gl_Position = attr_Position; - var_ScreenTex = attr_TexCoord0.xy; - //vec2 screenCoords = gl_Position.xy / gl_Position.w; - //var_ScreenTex = screenCoords * 0.5 + 0.5; -} diff --git a/code/renderergl2/glsl/texturecolor_fp.glsl b/code/renderergl2/glsl/texturecolor_fp.glsl deleted file mode 100644 index e077e7daf2..0000000000 --- a/code/renderergl2/glsl/texturecolor_fp.glsl +++ /dev/null @@ -1,12 +0,0 @@ -#version 120 - -uniform sampler2D u_DiffuseMap; -uniform vec4 u_Color; - -varying vec2 var_Tex1; - - -void main() -{ - gl_FragColor = texture2D(u_DiffuseMap, var_Tex1) * u_Color; -} diff --git a/code/renderergl2/glsl/texturecolor_vp.glsl b/code/renderergl2/glsl/texturecolor_vp.glsl deleted file mode 100644 index 7a5750a564..0000000000 --- a/code/renderergl2/glsl/texturecolor_vp.glsl +++ /dev/null @@ -1,15 +0,0 @@ -#version 120 - -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_Tex1; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - var_Tex1 = attr_TexCoord0.st; -} diff --git a/code/renderergl2/glsl/tonemap_fp.glsl b/code/renderergl2/glsl/tonemap_fp.glsl deleted file mode 100644 index 9b18de8a1c..0000000000 --- a/code/renderergl2/glsl/tonemap_fp.glsl +++ /dev/null @@ -1,48 +0,0 @@ -uniform sampler2D u_TextureMap; -uniform sampler2D u_LevelsMap; - -uniform vec4 u_Color; - -uniform vec2 u_AutoExposureMinMax; -uniform vec3 u_ToneMinAvgMaxLinear; - -varying vec2 var_TexCoords; - -const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721); //vec3(0.299, 0.587, 0.114); - -vec3 FilmicTonemap(vec3 x) -{ - const float SS = 0.22; // Shoulder Strength - const float LS = 0.30; // Linear Strength - const float LA = 0.10; // Linear Angle - const float TS = 0.20; // Toe Strength - const float TAN = 0.01; // Toe Angle Numerator - const float TAD = 0.30; // Toe Angle Denominator - - vec3 SSxx = SS * x * x; - vec3 LSx = LS * x; - vec3 LALSx = LSx * LA; - - return ((SSxx + LALSx + TS * TAN) / (SSxx + LSx + TS * TAD)) - TAN / TAD; - - //return ((x*(SS*x+LA*LS)+TS*TAN)/(x*(SS*x+LS)+TS*TAD)) - TAN/TAD; - -} - -void main() -{ - vec4 color = texture2D(u_TextureMap, var_TexCoords) * u_Color; - vec3 minAvgMax = texture2D(u_LevelsMap, var_TexCoords).rgb; - vec3 logMinAvgMaxLum = clamp(minAvgMax * 20.0 - 10.0, -u_AutoExposureMinMax.y, -u_AutoExposureMinMax.x); - - float avgLum = exp2(logMinAvgMaxLum.y); - //float maxLum = exp2(logMinAvgMaxLum.z); - - color.rgb *= u_ToneMinAvgMaxLinear.y / avgLum; - color.rgb = max(vec3(0.0), color.rgb - vec3(u_ToneMinAvgMaxLinear.x)); - - vec3 fWhite = 1.0 / FilmicTonemap(vec3(u_ToneMinAvgMaxLinear.z - u_ToneMinAvgMaxLinear.x)); - color.rgb = FilmicTonemap(color.rgb) * fWhite; - - gl_FragColor = clamp(color, 0.0, 1.0); -} diff --git a/code/renderergl2/glsl/tonemap_vp.glsl b/code/renderergl2/glsl/tonemap_vp.glsl deleted file mode 100644 index bdaa74af8e..0000000000 --- a/code/renderergl2/glsl/tonemap_vp.glsl +++ /dev/null @@ -1,13 +0,0 @@ -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_TexCoords; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - var_TexCoords = attr_TexCoord0.st; -} diff --git a/code/renderergl2/tr_animation.c b/code/renderergl2/tr_animation.c deleted file mode 100644 index a5f08986b6..0000000000 --- a/code/renderergl2/tr_animation.c +++ /dev/null @@ -1,522 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -/* - -All bones should be an identity orientation to display the mesh exactly -as it is specified. - -For all other frames, the bones represent the transformation from the -orientation of the bone in the base frame to the orientation in this -frame. - -*/ - - -// copied and adapted from tr_mesh.c - -/* -============= -R_MDRCullModel -============= -*/ - -static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) { - vec3_t bounds[2]; - mdrFrame_t *oldFrame, *newFrame; - int i, frameSize; - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - // compute frame pointers - newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe); - - // cull bounding sphere ONLY if this is not an upscaled entity - if ( !ent->e.nonNormalizedAxes ) - { - if ( ent->e.frame == ent->e.oldframe ) - { - switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) - { - // Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend - // we do. After all, the purpose of mdrs are not that different, are they? - - case CULL_OUT: - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - - case CULL_IN: - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - - case CULL_CLIP: - tr.pc.c_sphere_cull_md3_clip++; - break; - } - } - else - { - int sphereCull, sphereCullB; - - sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); - if ( newFrame == oldFrame ) { - sphereCullB = sphereCull; - } else { - sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); - } - - if ( sphereCull == sphereCullB ) - { - if ( sphereCull == CULL_OUT ) - { - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - } - else if ( sphereCull == CULL_IN ) - { - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - } - else - { - tr.pc.c_sphere_cull_md3_clip++; - } - } - } - } - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; - bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - -/* -================= -R_MDRComputeFogNum - -================= -*/ - -int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - mdrFrame_t *mdrFrame; - vec3_t localOrigin; - int frameSize; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - // FIXME: non-normalized axis issues - mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin ); - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - - -/* -============== -R_MDRAddAnimSurfaces -============== -*/ - -// much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c - -void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { - mdrHeader_t *header; - mdrSurface_t *surface; - mdrLOD_t *lod; - shader_t *shader; - skin_t *skin; - int i, j; - int lodnum = 0; - int fogNum = 0; - int cull; - int cubemapIndex; - qboolean personalModel; - - header = (mdrHeader_t *) tr.currentModel->modelData; - - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) - { - ent->e.frame %= header->numFrames; - ent->e.oldframe %= header->numFrames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ((ent->e.frame >= header->numFrames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= header->numFrames) - || (ent->e.oldframe < 0) ) - { - ri.Printf( PRINT_DEVELOPER, "R_MDRAddAnimSurfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_MDRCullModel (header, ent); - if ( cull == CULL_OUT ) { - return; - } - - // figure out the current LOD of the model we're rendering, and set the lod pointer respectively. - lodnum = R_ComputeLOD(ent); - // check whether this model has as that many LODs at all. If not, try the closest thing we got. - if(header->numLODs <= 0) - return; - if(header->numLODs <= lodnum) - lodnum = header->numLODs - 1; - - lod = (mdrLOD_t *)( (byte *)header + header->ofsLODs); - for(i = 0; i < lodnum; i++) - { - lod = (mdrLOD_t *) ((byte *) lod + lod->ofsEnd); - } - - // set up lighting - if ( !personalModel || r_shadows->integer > 1 ) - { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // fogNum? - fogNum = R_MDRComputeFogNum( header, ent ); - - cubemapIndex = R_CubemapForPoint(ent->e.origin); - - surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces ); - - for ( i = 0 ; i < lod->numSurfaces ; i++ ) - { - - if(ent->e.customShader) - shader = R_GetShaderByHandle(ent->e.customShader); - else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) - { - skin = R_GetSkinByHandle(ent->e.customSkin); - shader = tr.defaultShader; - - for(j = 0; j < skin->numSurfaces; j++) - { - if (!strcmp(skin->surfaces[j]->name, surface->name)) - { - shader = skin->surfaces[j]->shader; - break; - } - } - } - else if(surface->shaderIndex > 0) - shader = R_GetShaderByHandle( surface->shaderIndex ); - else - shader = tr.defaultShader; - - // we will add shadows even if the main object isn't visible in the view - - // stencil shadows can't do personal models unless I polyhedron clip - if ( !personalModel - && r_shadows->integer == 2 - && fogNum == 0 - && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) - && shader->sort == SS_OPAQUE ) - { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse, qfalse, 0 ); - } - - // projection shadows work fine with personal models - if ( r_shadows->integer == 3 - && fogNum == 0 - && (ent->e.renderfx & RF_SHADOW_PLANE ) - && shader->sort == SS_OPAQUE ) - { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse, 0 ); - } - - if (!personalModel) - R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse, cubemapIndex ); - - surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd ); - } -} - -/* -============== -RB_MDRSurfaceAnim -============== -*/ -void RB_MDRSurfaceAnim( mdrSurface_t *surface ) -{ - int i, j, k; - float frontlerp, backlerp; - int *triangles; - int indexes; - int baseIndex, baseVertex; - int numVerts; - mdrVertex_t *v; - mdrHeader_t *header; - mdrFrame_t *frame; - mdrFrame_t *oldFrame; - mdrBone_t bones[MDR_MAX_BONES], *bonePtr, *bone; - - int frameSize; - - // don't lerp if lerping off, or this is the only frame, or the last frame... - // - if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame) - { - backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used - frontlerp = 1; - } - else - { - backlerp = backEnd.currentEntity->e.backlerp; - frontlerp = 1.0f - backlerp; - } - - header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader); - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - frame = (mdrFrame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.frame * frameSize ); - oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.oldframe * frameSize ); - - RB_CheckOverflow( surface->numVerts, surface->numTriangles ); - - triangles = (int *) ((byte *)surface + surface->ofsTriangles); - indexes = surface->numTriangles * 3; - baseIndex = tess.numIndexes; - baseVertex = tess.numVertexes; - - // Set up all triangles. - for (j = 0 ; j < indexes ; j++) - { - tess.indexes[baseIndex + j] = baseVertex + triangles[j]; - } - tess.numIndexes += indexes; - - // - // lerp all the needed bones - // - if ( !backlerp ) - { - // no lerping needed - bonePtr = frame->bones; - } - else - { - bonePtr = bones; - - for ( i = 0 ; i < header->numBones*12 ; i++ ) - { - ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i]; - } - } - - // - // deform the vertexes by the lerped bones - // - numVerts = surface->numVerts; - v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts); - for ( j = 0; j < numVerts; j++ ) - { - vec3_t tempVert, tempNormal; - mdrWeight_t *w; - - VectorClear( tempVert ); - VectorClear( tempNormal ); - w = v->weights; - for ( k = 0 ; k < v->numWeights ; k++, w++ ) - { - bone = bonePtr + w->boneIndex; - - tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] ); - tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] ); - tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] ); - - tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal ); - tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal ); - tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal ); - } - - tess.xyz[baseVertex + j][0] = tempVert[0]; - tess.xyz[baseVertex + j][1] = tempVert[1]; - tess.xyz[baseVertex + j][2] = tempVert[2]; - - tess.normal[baseVertex + j] = R_VboPackNormal(tempNormal); - - tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; - tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; - - v = (mdrVertex_t *)&v->weights[v->numWeights]; - } - - tess.numVertexes += surface->numVerts; -} - - -#define MC_MASK_X ((1<<(MC_BITS_X))-1) -#define MC_MASK_Y ((1<<(MC_BITS_Y))-1) -#define MC_MASK_Z ((1<<(MC_BITS_Z))-1) -#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1) - -#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2)) - -#define MC_POS_X (0) -#define MC_SHIFT_X (0) - -#define MC_POS_Y ((((MC_BITS_X))/8)) -#define MC_SHIFT_Y ((((MC_BITS_X)%8))) - -#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8)) -#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8))) - -#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8)) -#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8))) - -#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8)) -#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8))) - -#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8)) -#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8))) - -#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8)) -#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8))) - -#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8)) -#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8))) - -#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8)) -#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8))) - -#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8)) -#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8))) - -#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8)) -#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8))) - -#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8)) -#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8))) - -void MC_UnCompress(float mat[3][4],const unsigned char * comp) -{ - int val; - - val=(int)((unsigned short *)(comp))[0]; - val-=1<<(MC_BITS_X-1); - mat[0][3]=((float)(val))*MC_SCALE_X; - - val=(int)((unsigned short *)(comp))[1]; - val-=1<<(MC_BITS_Y-1); - mat[1][3]=((float)(val))*MC_SCALE_Y; - - val=(int)((unsigned short *)(comp))[2]; - val-=1<<(MC_BITS_Z-1); - mat[2][3]=((float)(val))*MC_SCALE_Z; - - val=(int)((unsigned short *)(comp))[3]; - val-=1<<(MC_BITS_VECT-1); - mat[0][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[4]; - val-=1<<(MC_BITS_VECT-1); - mat[0][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[5]; - val-=1<<(MC_BITS_VECT-1); - mat[0][2]=((float)(val))*MC_SCALE_VECT; - - - val=(int)((unsigned short *)(comp))[6]; - val-=1<<(MC_BITS_VECT-1); - mat[1][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[7]; - val-=1<<(MC_BITS_VECT-1); - mat[1][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[8]; - val-=1<<(MC_BITS_VECT-1); - mat[1][2]=((float)(val))*MC_SCALE_VECT; - - - val=(int)((unsigned short *)(comp))[9]; - val-=1<<(MC_BITS_VECT-1); - mat[2][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[10]; - val-=1<<(MC_BITS_VECT-1); - mat[2][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[11]; - val-=1<<(MC_BITS_VECT-1); - mat[2][2]=((float)(val))*MC_SCALE_VECT; -} diff --git a/code/renderergl2/tr_backend.c b/code/renderergl2/tr_backend.c deleted file mode 100644 index e4431cf529..0000000000 --- a/code/renderergl2/tr_backend.c +++ /dev/null @@ -1,1783 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -backEndData_t *backEndData; -backEndState_t backEnd; - - -static float s_flipMatrix[16] = { - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 -}; - - -/* -** GL_Bind -*/ -void GL_Bind( image_t *image ) { - int texnum; - - if ( !image ) { - ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" ); - texnum = tr.defaultImage->texnum; - } else { - texnum = image->texnum; - } - - if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option - texnum = tr.dlightImage->texnum; - } - - if ( glState.currenttextures[glState.currenttmu] != texnum ) { - if ( image ) { - image->frameUsed = tr.frameCount; - } - glState.currenttextures[glState.currenttmu] = texnum; - if (image && image->flags & IMGFLAG_CUBEMAP) - qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum ); - else - qglBindTexture( GL_TEXTURE_2D, texnum ); - } -} - -/* -** GL_SelectTexture -*/ -void GL_SelectTexture( int unit ) -{ - if ( glState.currenttmu == unit ) - { - return; - } - - if (!(unit >= 0 && unit <= 31)) - ri.Error( ERR_DROP, "GL_SelectTexture: unit = %i", unit ); - - qglActiveTextureARB( GL_TEXTURE0_ARB + unit ); - - glState.currenttmu = unit; -} - -/* -** GL_BindToTMU -*/ -void GL_BindToTMU( image_t *image, int tmu ) -{ - int texnum; - int oldtmu = glState.currenttmu; - - if (!image) - texnum = 0; - else - texnum = image->texnum; - - if ( glState.currenttextures[tmu] != texnum ) { - GL_SelectTexture( tmu ); - if (image) - image->frameUsed = tr.frameCount; - glState.currenttextures[tmu] = texnum; - - if (image && (image->flags & IMGFLAG_CUBEMAP)) - qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum ); - else - qglBindTexture( GL_TEXTURE_2D, texnum ); - GL_SelectTexture( oldtmu ); - } -} - - -/* -** GL_Cull -*/ -void GL_Cull( int cullType ) { - if ( glState.faceCulling == cullType ) { - return; - } - - glState.faceCulling = cullType; - - if ( cullType == CT_TWO_SIDED ) - { - qglDisable( GL_CULL_FACE ); - } - else - { - qboolean cullFront; - qglEnable( GL_CULL_FACE ); - - cullFront = (cullType == CT_FRONT_SIDED); - if ( backEnd.viewParms.isMirror ) - { - cullFront = !cullFront; - } - - if ( backEnd.currentEntity && backEnd.currentEntity->mirrored ) - { - cullFront = !cullFront; - } - - qglCullFace( cullFront ? GL_FRONT : GL_BACK ); - } -} - -/* -** GL_TexEnv -*/ -void GL_TexEnv( int env ) -{ - if ( env == glState.texEnv[glState.currenttmu] ) - { - return; - } - - glState.texEnv[glState.currenttmu] = env; - - - switch ( env ) - { - case GL_MODULATE: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - break; - case GL_REPLACE: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); - break; - case GL_DECAL: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); - break; - case GL_ADD: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD ); - break; - default: - ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed", env ); - break; - } -} - -/* -** GL_State -** -** This routine is responsible for setting the most commonly changed state -** in Q3. -*/ -void GL_State( unsigned long stateBits ) -{ - unsigned long diff = stateBits ^ glState.glStateBits; - - if ( !diff ) - { - return; - } - - // - // check depthFunc bits - // - if ( diff & GLS_DEPTHFUNC_BITS ) - { - if ( stateBits & GLS_DEPTHFUNC_EQUAL ) - { - qglDepthFunc( GL_EQUAL ); - } - else if ( stateBits & GLS_DEPTHFUNC_GREATER) - { - qglDepthFunc( GL_GREATER ); - } - else - { - qglDepthFunc( GL_LEQUAL ); - } - } - - // - // check blend bits - // - if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) - { - GLenum srcFactor = GL_ONE, dstFactor = GL_ONE; - - if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) - { - switch ( stateBits & GLS_SRCBLEND_BITS ) - { - case GLS_SRCBLEND_ZERO: - srcFactor = GL_ZERO; - break; - case GLS_SRCBLEND_ONE: - srcFactor = GL_ONE; - break; - case GLS_SRCBLEND_DST_COLOR: - srcFactor = GL_DST_COLOR; - break; - case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: - srcFactor = GL_ONE_MINUS_DST_COLOR; - break; - case GLS_SRCBLEND_SRC_ALPHA: - srcFactor = GL_SRC_ALPHA; - break; - case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: - srcFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - case GLS_SRCBLEND_DST_ALPHA: - srcFactor = GL_DST_ALPHA; - break; - case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: - srcFactor = GL_ONE_MINUS_DST_ALPHA; - break; - case GLS_SRCBLEND_ALPHA_SATURATE: - srcFactor = GL_SRC_ALPHA_SATURATE; - break; - default: - ri.Error( ERR_DROP, "GL_State: invalid src blend state bits" ); - break; - } - - switch ( stateBits & GLS_DSTBLEND_BITS ) - { - case GLS_DSTBLEND_ZERO: - dstFactor = GL_ZERO; - break; - case GLS_DSTBLEND_ONE: - dstFactor = GL_ONE; - break; - case GLS_DSTBLEND_SRC_COLOR: - dstFactor = GL_SRC_COLOR; - break; - case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: - dstFactor = GL_ONE_MINUS_SRC_COLOR; - break; - case GLS_DSTBLEND_SRC_ALPHA: - dstFactor = GL_SRC_ALPHA; - break; - case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: - dstFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - case GLS_DSTBLEND_DST_ALPHA: - dstFactor = GL_DST_ALPHA; - break; - case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: - dstFactor = GL_ONE_MINUS_DST_ALPHA; - break; - default: - ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits" ); - break; - } - - qglEnable( GL_BLEND ); - qglBlendFunc( srcFactor, dstFactor ); - } - else - { - qglDisable( GL_BLEND ); - } - } - - // - // check depthmask - // - if ( diff & GLS_DEPTHMASK_TRUE ) - { - if ( stateBits & GLS_DEPTHMASK_TRUE ) - { - qglDepthMask( GL_TRUE ); - } - else - { - qglDepthMask( GL_FALSE ); - } - } - - // - // fill/line mode - // - if ( diff & GLS_POLYMODE_LINE ) - { - if ( stateBits & GLS_POLYMODE_LINE ) - { - qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); - } - else - { - qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - } - } - - // - // depthtest - // - if ( diff & GLS_DEPTHTEST_DISABLE ) - { - if ( stateBits & GLS_DEPTHTEST_DISABLE ) - { - qglDisable( GL_DEPTH_TEST ); - } - else - { - qglEnable( GL_DEPTH_TEST ); - } - } - - // - // alpha test - // - if ( diff & GLS_ATEST_BITS ) - { - switch ( stateBits & GLS_ATEST_BITS ) - { - case 0: - qglDisable( GL_ALPHA_TEST ); - break; - case GLS_ATEST_GT_0: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_GREATER, 0.0f ); - break; - case GLS_ATEST_LT_80: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_LESS, 0.5f ); - break; - case GLS_ATEST_GE_80: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_GEQUAL, 0.5f ); - break; - default: - assert( 0 ); - break; - } - } - - glState.glStateBits = stateBits; -} - - -void GL_SetProjectionMatrix(mat4_t matrix) -{ - Mat4Copy(matrix, glState.projection); - Mat4Multiply(glState.projection, glState.modelview, glState.modelviewProjection); -} - - -void GL_SetModelviewMatrix(mat4_t matrix) -{ - Mat4Copy(matrix, glState.modelview); - Mat4Multiply(glState.projection, glState.modelview, glState.modelviewProjection); -} - - -/* -================ -RB_Hyperspace - -A player has predicted a teleport, but hasn't arrived yet -================ -*/ -static void RB_Hyperspace( void ) { - float c; - - if ( !backEnd.isHyperspace ) { - // do initialization shit - } - - c = ( backEnd.refdef.time & 255 ) / 255.0f; - qglClearColor( c, c, c, 1 ); - qglClear( GL_COLOR_BUFFER_BIT ); - - backEnd.isHyperspace = qtrue; -} - - -static void SetViewportAndScissor( void ) { - GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); - - // set the window clipping - qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, - backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); - qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, - backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); -} - -/* -================= -RB_BeginDrawingView - -Any mirrored or portaled views have already been drawn, so prepare -to actually render the visible surfaces for this view -================= -*/ -void RB_BeginDrawingView (void) { - int clearBits = 0; - - // sync with gl if needed - if ( r_finish->integer == 1 && !glState.finishCalled ) { - qglFinish (); - glState.finishCalled = qtrue; - } - if ( r_finish->integer == 0 ) { - glState.finishCalled = qtrue; - } - - // we will need to change the projection matrix before drawing - // 2D images again - backEnd.projection2D = qfalse; - - if (glRefConfig.framebufferObject) - { - // FIXME: HUGE HACK: render to the screen fbo if we've already postprocessed the frame and aren't drawing more world - // drawing more world check is in case of double renders, such as skyportals - if (backEnd.viewParms.targetFbo == NULL) - { - if (!tr.renderFbo || (backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL))) - { - FBO_Bind(NULL); - } - else - { - FBO_Bind(tr.renderFbo); - } - } - else - { - FBO_Bind(backEnd.viewParms.targetFbo); - - // FIXME: hack for cubemap testing - if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) - { - //qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, backEnd.viewParms.targetFbo->colorImage[0]->texnum, 0); - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex]->texnum, 0); - } - } - } - - // - // set the modelview matrix for the viewer - // - SetViewportAndScissor(); - - // ensures that depth writes are enabled for the depth clear - GL_State( GLS_DEFAULT ); - // clear relevant buffers - clearBits = GL_DEPTH_BUFFER_BIT; - - if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) - { - clearBits |= GL_STENCIL_BUFFER_BIT; - } - if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) - { - clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used -#ifdef _DEBUG - qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky -#else - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky -#endif - } - - // clear to white for shadow maps - if (backEnd.viewParms.flags & VPF_SHADOWMAP) - { - clearBits |= GL_COLOR_BUFFER_BIT; - qglClearColor( 1.0f, 1.0f, 1.0f, 1.0f ); - } - - // clear to black for cube maps - if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) - { - clearBits |= GL_COLOR_BUFFER_BIT; - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - } - - qglClear( clearBits ); - - if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) - { - RB_Hyperspace(); - return; - } - else - { - backEnd.isHyperspace = qfalse; - } - - glState.faceCulling = -1; // force face culling to set next time - - // we will only draw a sun if there was sky rendered in this view - backEnd.skyRenderedThisView = qfalse; - - // clip to the plane of the portal - if ( backEnd.viewParms.isPortal ) { -#if 0 - float plane[4]; - double plane2[4]; - - plane[0] = backEnd.viewParms.portalPlane.normal[0]; - plane[1] = backEnd.viewParms.portalPlane.normal[1]; - plane[2] = backEnd.viewParms.portalPlane.normal[2]; - plane[3] = backEnd.viewParms.portalPlane.dist; - - plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); - plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); - plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); - plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; -#endif - GL_SetModelviewMatrix( s_flipMatrix ); - } -} - - -#define MAC_EVENT_PUMP_MSEC 5 - -/* -================== -RB_RenderDrawSurfList -================== -*/ -void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { - shader_t *shader, *oldShader; - int fogNum, oldFogNum; - int entityNum, oldEntityNum; - int dlighted, oldDlighted; - int pshadowed, oldPshadowed; - int cubemapIndex, oldCubemapIndex; - qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; - int i; - drawSurf_t *drawSurf; - int oldSort; - float originalTime; - FBO_t* fbo = NULL; - qboolean inQuery = qfalse; - - float depth[2]; - - - // save original time for entity shader offsets - originalTime = backEnd.refdef.floatTime; - - fbo = glState.currentFBO; - - // draw everything - oldEntityNum = -1; - backEnd.currentEntity = &tr.worldEntity; - oldShader = NULL; - oldFogNum = -1; - oldDepthRange = qfalse; - wasCrosshair = qfalse; - oldDlighted = qfalse; - oldPshadowed = qfalse; - oldCubemapIndex = -1; - oldSort = -1; - - depth[0] = 0.f; - depth[1] = 1.f; - - backEnd.pc.c_surfaces += numDrawSurfs; - - for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { - if ( drawSurf->sort == oldSort && drawSurf->cubemapIndex == oldCubemapIndex) { - if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) - continue; - - // fast path, same as previous sort - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - continue; - } - oldSort = drawSurf->sort; - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); - cubemapIndex = drawSurf->cubemapIndex; - - // - // change the tess parameters if needed - // a "entityMergable" shader is a shader that can have surfaces from seperate - // entities merged into a single batch, like smoke and blood puff sprites - if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || cubemapIndex != oldCubemapIndex - || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { - if (oldShader != NULL) { - RB_EndSurface(); - } - RB_BeginSurface( shader, fogNum, cubemapIndex ); - backEnd.pc.c_surfBatches++; - oldShader = shader; - oldFogNum = fogNum; - oldDlighted = dlighted; - oldPshadowed = pshadowed; - oldCubemapIndex = cubemapIndex; - } - - if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) - continue; - - // - // change the modelview matrix if needed - // - if ( entityNum != oldEntityNum ) { - qboolean sunflare = qfalse; - depthRange = isCrosshair = qfalse; - - if ( entityNum != REFENTITYNUM_WORLD ) { - backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; - backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; - // we have to reset the shaderTime as well otherwise image animations start - // from the wrong frame - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - - // set up the transformation matrix - R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); - - // set up the dynamic lighting if needed - if ( backEnd.currentEntity->needDlights ) { - R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); - } - - if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) - { - // hack the depth range to prevent view model from poking into walls - depthRange = qtrue; - - if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) - isCrosshair = qtrue; - } - } else { - backEnd.currentEntity = &tr.worldEntity; - backEnd.refdef.floatTime = originalTime; - backEnd.or = backEnd.viewParms.world; - // we have to reset the shaderTime as well otherwise image animations on - // the world (like water) continue with the wrong frame - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); - } - - GL_SetModelviewMatrix( backEnd.or.modelMatrix ); - - // - // change depthrange. Also change projection matrix so first person weapon does not look like coming - // out of the screen. - // - if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) - { - if (depthRange) - { - if(backEnd.viewParms.stereoFrame != STEREO_CENTER) - { - if(isCrosshair) - { - if(oldDepthRange) - { - // was not a crosshair but now is, change back proj matrix - GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); - } - } - else - { - viewParms_t temp = backEnd.viewParms; - - R_SetupProjection(&temp, r_znear->value, 0, qfalse); - - GL_SetProjectionMatrix( temp.projectionMatrix ); - } - } - - if(!oldDepthRange) - { - depth[0] = 0; - depth[1] = 0.3f; - qglDepthRange (depth[0], depth[1]); - } - } - else - { - if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) - { - GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); - } - - if (!sunflare) - qglDepthRange (0, 1); - - depth[0] = 0; - depth[1] = 1; - } - - oldDepthRange = depthRange; - wasCrosshair = isCrosshair; - } - - oldEntityNum = entityNum; - } - - // add the triangles for this surface - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - } - - backEnd.refdef.floatTime = originalTime; - - // draw the contents of the last shader batch - if (oldShader != NULL) { - RB_EndSurface(); - } - - if (inQuery) { - qglEndQueryARB(GL_SAMPLES_PASSED_ARB); - } - - if (glRefConfig.framebufferObject) - FBO_Bind(fbo); - - // go back to the world modelview matrix - - GL_SetModelviewMatrix( backEnd.viewParms.world.modelMatrix ); - - qglDepthRange (0, 1); -} - - -/* -============================================================================ - -RENDER BACK END FUNCTIONS - -============================================================================ -*/ - -/* -================ -RB_SetGL2D - -================ -*/ -void RB_SetGL2D (void) { - mat4_t matrix; - int width, height; - - if (backEnd.projection2D && backEnd.last2DFBO == glState.currentFBO) - return; - - backEnd.projection2D = qtrue; - backEnd.last2DFBO = glState.currentFBO; - - if (glState.currentFBO) - { - width = glState.currentFBO->width; - height = glState.currentFBO->height; - } - else - { - width = glConfig.vidWidth; - height = glConfig.vidHeight; - } - - // set 2D virtual screen size - qglViewport( 0, 0, width, height ); - qglScissor( 0, 0, width, height ); - - Mat4Ortho(0, width, height, 0, 0, 1, matrix); - GL_SetProjectionMatrix(matrix); - Mat4Identity(matrix); - GL_SetModelviewMatrix(matrix); - - GL_State( GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - - qglDisable( GL_CULL_FACE ); - qglDisable( GL_CLIP_PLANE0 ); - - // set time for 2D shaders - backEnd.refdef.time = ri.Milliseconds(); - backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f; - - // reset color scaling - backEnd.refdef.colorScale = 1.0f; -} - - -/* -============= -RE_StretchRaw - -FIXME: not exactly backend -Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. -Used for cinematics. -============= -*/ -void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { - int i, j; - int start, end; - vec4_t quadVerts[4]; - vec2_t texCoords[4]; - - if ( !tr.registered ) { - return; - } - R_IssuePendingRenderCommands(); - - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - // we definately want to sync every frame for the cinematics - qglFinish(); - - start = 0; - if ( r_speeds->integer ) { - start = ri.Milliseconds(); - } - - // make sure rows and cols are powers of 2 - for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { - } - for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { - } - if ( ( 1 << i ) != cols || ( 1 << j ) != rows) { - ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); - } - - RE_UploadCinematic (w, h, cols, rows, data, client, dirty); - - if ( r_speeds->integer ) { - end = ri.Milliseconds(); - ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); - } - - // FIXME: HUGE hack - if (glRefConfig.framebufferObject) - { - if (!tr.renderFbo || backEnd.framePostProcessed) - { - FBO_Bind(NULL); - } - else - { - FBO_Bind(tr.renderFbo); - } - } - - RB_SetGL2D(); - - VectorSet4(quadVerts[0], x, y, 0.0f, 1.0f); - VectorSet4(quadVerts[1], x + w, y, 0.0f, 1.0f); - VectorSet4(quadVerts[2], x + w, y + h, 0.0f, 1.0f); - VectorSet4(quadVerts[3], x, y + h, 0.0f, 1.0f); - - VectorSet2(texCoords[0], 0.5f / cols, 0.5f / rows); - VectorSet2(texCoords[1], (cols - 0.5f) / cols, 0.5f / rows); - VectorSet2(texCoords[2], (cols - 0.5f) / cols, (rows - 0.5f) / rows); - VectorSet2(texCoords[3], 0.5f / cols, (rows - 0.5f) / rows); - - GLSL_BindProgram(&tr.textureColorShader); - - GLSL_SetUniformMat4(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite); - - RB_InstantQuad2(quadVerts, texCoords); -} - -void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { - - GL_Bind( tr.scratchImage[client] ); - - // if the scratchImage isn't in the format we want, specify it as a new texture - if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { - tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; - tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; - qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - } else { - if (dirty) { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression - qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); - } - } -} - - -/* -============= -RB_SetColor - -============= -*/ -const void *RB_SetColor( const void *data ) { - const setColorCommand_t *cmd; - - cmd = (const setColorCommand_t *)data; - - backEnd.color2D[0] = cmd->color[0] * 255; - backEnd.color2D[1] = cmd->color[1] * 255; - backEnd.color2D[2] = cmd->color[2] * 255; - backEnd.color2D[3] = cmd->color[3] * 255; - - return (const void *)(cmd + 1); -} - -/* -============= -RB_StretchPic -============= -*/ -const void *RB_StretchPic ( const void *data ) { - const stretchPicCommand_t *cmd; - shader_t *shader; - int numVerts, numIndexes; - - cmd = (const stretchPicCommand_t *)data; - - // FIXME: HUGE hack - if (glRefConfig.framebufferObject) - { - if (!tr.renderFbo || backEnd.framePostProcessed) - { - FBO_Bind(NULL); - } - else - { - FBO_Bind(tr.renderFbo); - } - } - - RB_SetGL2D(); - - shader = cmd->shader; - if ( shader != tess.shader ) { - if ( tess.numIndexes ) { - RB_EndSurface(); - } - backEnd.currentEntity = &backEnd.entity2D; - RB_BeginSurface( shader, 0, 0 ); - } - - RB_CHECKOVERFLOW( 4, 6 ); - numVerts = tess.numVertexes; - numIndexes = tess.numIndexes; - - tess.numVertexes += 4; - tess.numIndexes += 6; - - tess.indexes[ numIndexes ] = numVerts + 3; - tess.indexes[ numIndexes + 1 ] = numVerts + 0; - tess.indexes[ numIndexes + 2 ] = numVerts + 2; - tess.indexes[ numIndexes + 3 ] = numVerts + 2; - tess.indexes[ numIndexes + 4 ] = numVerts + 0; - tess.indexes[ numIndexes + 5 ] = numVerts + 1; - - { - vec4_t color; - - VectorScale4(backEnd.color2D, 1.0f / 255.0f, color); - - VectorCopy4(color, tess.vertexColors[ numVerts ]); - VectorCopy4(color, tess.vertexColors[ numVerts + 1]); - VectorCopy4(color, tess.vertexColors[ numVerts + 2]); - VectorCopy4(color, tess.vertexColors[ numVerts + 3 ]); - } - - tess.xyz[ numVerts ][0] = cmd->x; - tess.xyz[ numVerts ][1] = cmd->y; - tess.xyz[ numVerts ][2] = 0; - - tess.texCoords[ numVerts ][0][0] = cmd->s1; - tess.texCoords[ numVerts ][0][1] = cmd->t1; - - tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w; - tess.xyz[ numVerts + 1 ][1] = cmd->y; - tess.xyz[ numVerts + 1 ][2] = 0; - - tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2; - tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1; - - tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w; - tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h; - tess.xyz[ numVerts + 2 ][2] = 0; - - tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2; - tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2; - - tess.xyz[ numVerts + 3 ][0] = cmd->x; - tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h; - tess.xyz[ numVerts + 3 ][2] = 0; - - tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1; - tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2; - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_DrawSurfs - -============= -*/ -const void *RB_DrawSurfs( const void *data ) { - const drawSurfsCommand_t *cmd; - - // finish any 2D drawing if needed - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - cmd = (const drawSurfsCommand_t *)data; - - backEnd.refdef = cmd->refdef; - backEnd.viewParms = cmd->viewParms; - - // clear the z buffer, set the modelview, etc - RB_BeginDrawingView (); - - if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) - { - qglEnable(GL_DEPTH_CLAMP); - } - - if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || (backEnd.viewParms.flags & VPF_DEPTHSHADOW))) - { - FBO_t *oldFbo = glState.currentFBO; - - backEnd.depthFill = qtrue; - qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); - qglColorMask(!backEnd.colorMask[0], !backEnd.colorMask[1], !backEnd.colorMask[2], !backEnd.colorMask[3]); - backEnd.depthFill = qfalse; - - if (tr.msaaResolveFbo) - { - // If we're using multisampling, resolve the depth first - FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST); - } - else if (tr.renderFbo == NULL) - { - // If we're rendering directly to the screen, copy the depth to a texture - GL_BindToTMU(tr.renderDepthImage, 0); - qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0); - } - - if (r_ssao->integer) - { - // need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image - FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0); - } - - if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT) - { - vec4_t quadVerts[4]; - vec2_t texCoords[4]; - vec4_t box; - - FBO_Bind(tr.screenShadowFbo); - - box[0] = backEnd.viewParms.viewportX * tr.screenShadowFbo->width / (float)glConfig.vidWidth; - box[1] = backEnd.viewParms.viewportY * tr.screenShadowFbo->height / (float)glConfig.vidHeight; - box[2] = backEnd.viewParms.viewportWidth * tr.screenShadowFbo->width / (float)glConfig.vidWidth; - box[3] = backEnd.viewParms.viewportHeight * tr.screenShadowFbo->height / (float)glConfig.vidHeight; - - qglViewport(box[0], box[1], box[2], box[3]); - qglScissor(box[0], box[1], box[2], box[3]); - - box[0] = backEnd.viewParms.viewportX / (float)glConfig.vidWidth; - box[1] = backEnd.viewParms.viewportY / (float)glConfig.vidHeight; - box[2] = box[0] + backEnd.viewParms.viewportWidth / (float)glConfig.vidWidth; - box[3] = box[1] + backEnd.viewParms.viewportHeight / (float)glConfig.vidHeight; - - texCoords[0][0] = box[0]; texCoords[0][1] = box[3]; - texCoords[1][0] = box[2]; texCoords[1][1] = box[3]; - texCoords[2][0] = box[2]; texCoords[2][1] = box[1]; - texCoords[3][0] = box[0]; texCoords[3][1] = box[1]; - - box[0] = -1.0f; - box[1] = -1.0f; - box[2] = 1.0f; - box[3] = 1.0f; - - VectorSet4(quadVerts[0], box[0], box[3], 0, 1); - VectorSet4(quadVerts[1], box[2], box[3], 0, 1); - VectorSet4(quadVerts[2], box[2], box[1], 0, 1); - VectorSet4(quadVerts[3], box[0], box[1], 0, 1); - - GL_State( GLS_DEPTHTEST_DISABLE ); - - GLSL_BindProgram(&tr.shadowmaskShader); - - GL_BindToTMU(tr.renderDepthImage, TB_COLORMAP); - GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP); - GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); - GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); - - GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); - GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); - GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); - - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg); - { - vec4_t viewInfo; - vec3_t viewVector; - - float zmax = backEnd.viewParms.zFar; - float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f); - float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f); - - float zmin = r_znear->value; - - VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector); - VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWLEFT, viewVector); - VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP, viewVector); - - VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - - GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo); - } - - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - } - - if (r_ssao->integer) - { - vec4_t quadVerts[4]; - vec2_t texCoords[4]; - - FBO_Bind(tr.quarterFbo[0]); - - qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); - qglScissor(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); - - VectorSet4(quadVerts[0], -1, 1, 0, 1); - VectorSet4(quadVerts[1], 1, 1, 0, 1); - VectorSet4(quadVerts[2], 1, -1, 0, 1); - VectorSet4(quadVerts[3], -1, -1, 0, 1); - - texCoords[0][0] = 0; texCoords[0][1] = 1; - texCoords[1][0] = 1; texCoords[1][1] = 1; - texCoords[2][0] = 1; texCoords[2][1] = 0; - texCoords[3][0] = 0; texCoords[3][1] = 0; - - GL_State( GLS_DEPTHTEST_DISABLE ); - - GLSL_BindProgram(&tr.ssaoShader); - - GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP); - - { - vec4_t viewInfo; - - float zmax = backEnd.viewParms.zFar; - float zmin = r_znear->value; - - VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - - GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo); - } - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - - - FBO_Bind(tr.quarterFbo[1]); - - qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); - qglScissor(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); - - GLSL_BindProgram(&tr.depthBlurShader[0]); - - GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP); - GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); - - { - vec4_t viewInfo; - - float zmax = backEnd.viewParms.zFar; - float zmin = r_znear->value; - - VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - - GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo); - } - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - - - FBO_Bind(tr.screenSsaoFbo); - - qglViewport(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); - qglScissor(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); - - GLSL_BindProgram(&tr.depthBlurShader[1]); - - GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP); - GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); - - { - vec4_t viewInfo; - - float zmax = backEnd.viewParms.zFar; - float zmin = r_znear->value; - - VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - - GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo); - } - - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - } - - // reset viewport and scissor - FBO_Bind(oldFbo); - SetViewportAndScissor(); - } - - if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) - { - qglDisable(GL_DEPTH_CLAMP); - } - - if (!(backEnd.viewParms.flags & VPF_DEPTHSHADOW)) - { - RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); - - if (r_drawSun->integer) - { - RB_DrawSun(0.1, tr.sunShader); - } - - if (r_drawSunRays->integer) - { - FBO_t *oldFbo = glState.currentFBO; - FBO_Bind(tr.sunRaysFbo); - - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - qglClear( GL_COLOR_BUFFER_BIT ); - - if (glRefConfig.occlusionQuery) - { - tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue; - qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]); - } - - RB_DrawSun(0.3, tr.sunFlareShader); - - if (glRefConfig.occlusionQuery) - { - qglEndQueryARB(GL_SAMPLES_PASSED_ARB); - } - - FBO_Bind(oldFbo); - } - - // darken down any stencil shadows - RB_ShadowFinish(); - - // add light flares on lights that aren't obscured - RB_RenderFlares(); - } - - if (glRefConfig.framebufferObject && tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) - { - FBO_Bind(NULL); - GL_SelectTexture(TB_CUBEMAP); - GL_BindToTMU(tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex], TB_CUBEMAP); - qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP); - GL_SelectTexture(0); - } - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_DrawBuffer - -============= -*/ -const void *RB_DrawBuffer( const void *data ) { - const drawBufferCommand_t *cmd; - - cmd = (const drawBufferCommand_t *)data; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - if (glRefConfig.framebufferObject) - FBO_Bind(NULL); - - qglDrawBuffer( cmd->buffer ); - - // clear screen for debugging - if ( r_clear->integer ) { - qglClearColor( 1, 0, 0.5, 1 ); - qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - } - - return (const void *)(cmd + 1); -} - -/* -=============== -RB_ShowImages - -Draw all the images to the screen, on top of whatever -was there. This is used to test for texture thrashing. - -Also called by RE_EndRegistration -=============== -*/ -void RB_ShowImages( void ) { - int i; - image_t *image; - float x, y, w, h; - int start, end; - - RB_SetGL2D(); - - qglClear( GL_COLOR_BUFFER_BIT ); - - qglFinish(); - - start = ri.Milliseconds(); - - for ( i=0 ; iinteger == 2 ) { - w *= image->uploadWidth / 512.0f; - h *= image->uploadHeight / 512.0f; - } - - { - vec4_t quadVerts[4]; - - GL_Bind(image); - - VectorSet4(quadVerts[0], x, y, 0, 1); - VectorSet4(quadVerts[1], x + w, y, 0, 1); - VectorSet4(quadVerts[2], x + w, y + h, 0, 1); - VectorSet4(quadVerts[3], x, y + h, 0, 1); - - RB_InstantQuad(quadVerts); - } - } - - qglFinish(); - - end = ri.Milliseconds(); - ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); - -} - -/* -============= -RB_ColorMask - -============= -*/ -const void *RB_ColorMask(const void *data) -{ - const colorMaskCommand_t *cmd = data; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - if (glRefConfig.framebufferObject) - { - // reverse color mask, so 0 0 0 0 is the default - backEnd.colorMask[0] = !cmd->rgba[0]; - backEnd.colorMask[1] = !cmd->rgba[1]; - backEnd.colorMask[2] = !cmd->rgba[2]; - backEnd.colorMask[3] = !cmd->rgba[3]; - } - - qglColorMask(cmd->rgba[0], cmd->rgba[1], cmd->rgba[2], cmd->rgba[3]); - - return (const void *)(cmd + 1); -} - -/* -============= -RB_ClearDepth - -============= -*/ -const void *RB_ClearDepth(const void *data) -{ - const clearDepthCommand_t *cmd = data; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - // texture swapping test - if (r_showImages->integer) - RB_ShowImages(); - - if (glRefConfig.framebufferObject) - { - if (!tr.renderFbo || backEnd.framePostProcessed) - { - FBO_Bind(NULL); - } - else - { - FBO_Bind(tr.renderFbo); - } - } - - qglClear(GL_DEPTH_BUFFER_BIT); - - // if we're doing MSAA, clear the depth texture for the resolve buffer - if (tr.msaaResolveFbo) - { - FBO_Bind(tr.msaaResolveFbo); - qglClear(GL_DEPTH_BUFFER_BIT); - } - - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_SwapBuffers - -============= -*/ -const void *RB_SwapBuffers( const void *data ) { - const swapBuffersCommand_t *cmd; - - // finish any 2D drawing if needed - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - // texture swapping test - if ( r_showImages->integer ) { - RB_ShowImages(); - } - - cmd = (const swapBuffersCommand_t *)data; - - // we measure overdraw by reading back the stencil buffer and - // counting up the number of increments that have happened - if ( r_measureOverdraw->integer ) { - int i; - long sum = 0; - unsigned char *stencilReadback; - - stencilReadback = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight ); - qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); - - for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) { - sum += stencilReadback[i]; - } - - backEnd.pc.c_overDraw += sum; - ri.Hunk_FreeTempMemory( stencilReadback ); - } - - if (glRefConfig.framebufferObject) - { - if (!backEnd.framePostProcessed) - { - if (tr.msaaResolveFbo && r_hdr->integer) - { - // Resolving an RGB16F MSAA FBO to the screen messes with the brightness, so resolve to an RGB16F FBO first - FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); - FBO_FastBlit(tr.msaaResolveFbo, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - else if (tr.renderFbo) - { - FBO_FastBlit(tr.renderFbo, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - } - } - - if ( !glState.finishCalled ) { - qglFinish(); - } - - GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" ); - - GLimp_EndFrame(); - - backEnd.framePostProcessed = qfalse; - backEnd.projection2D = qfalse; - - return (const void *)(cmd + 1); -} - -/* -============= -RB_CapShadowMap - -============= -*/ -const void *RB_CapShadowMap(const void *data) -{ - const capShadowmapCommand_t *cmd = data; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - if (cmd->map != -1) - { - GL_SelectTexture(0); - if (cmd->cubeSide != -1) - { - if (tr.shadowCubemaps[cmd->map]) - { - GL_Bind(tr.shadowCubemaps[cmd->map]); - qglCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); - } - } - else - { - if (tr.pshadowMaps[cmd->map]) - { - GL_Bind(tr.pshadowMaps[cmd->map]); - qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); - } - } - } - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_PostProcess - -============= -*/ -const void *RB_PostProcess(const void *data) -{ - const postProcessCommand_t *cmd = data; - FBO_t *srcFbo; - ivec4_t srcBox, dstBox; - qboolean autoExposure; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - if (!glRefConfig.framebufferObject || !r_postProcess->integer) - { - // do nothing - return (const void *)(cmd + 1); - } - - if (cmd) - { - backEnd.refdef = cmd->refdef; - backEnd.viewParms = cmd->viewParms; - } - - srcFbo = tr.renderFbo; - if (tr.msaaResolveFbo) - { - // Resolve the MSAA before anything else - // Can't resolve just part of the MSAA FBO, so multiple views will suffer a performance hit here - FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); - srcFbo = tr.msaaResolveFbo; - } - - dstBox[0] = backEnd.viewParms.viewportX; - dstBox[1] = backEnd.viewParms.viewportY; - dstBox[2] = backEnd.viewParms.viewportWidth; - dstBox[3] = backEnd.viewParms.viewportHeight; - - if (r_ssao->integer) - { - srcBox[0] = backEnd.viewParms.viewportX * tr.screenSsaoImage->width / (float)glConfig.vidWidth; - srcBox[1] = backEnd.viewParms.viewportY * tr.screenSsaoImage->height / (float)glConfig.vidHeight; - srcBox[2] = backEnd.viewParms.viewportWidth * tr.screenSsaoImage->width / (float)glConfig.vidWidth; - srcBox[3] = backEnd.viewParms.viewportHeight * tr.screenSsaoImage->height / (float)glConfig.vidHeight; - - //FBO_BlitFromTexture(tr.screenSsaoImage, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); - srcBox[1] = tr.screenSsaoImage->height - srcBox[1]; - srcBox[3] = -srcBox[3]; - - FBO_Blit(tr.screenSsaoFbo, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); - } - - srcBox[0] = backEnd.viewParms.viewportX; - srcBox[1] = backEnd.viewParms.viewportY; - srcBox[2] = backEnd.viewParms.viewportWidth; - srcBox[3] = backEnd.viewParms.viewportHeight; - - if (srcFbo) - { - if (r_hdr->integer && (r_toneMap->integer || r_forceToneMap->integer)) - { - autoExposure = r_autoExposure->integer || r_forceAutoExposure->integer; - RB_ToneMap(srcFbo, srcBox, NULL, dstBox, autoExposure); - } - else if (r_cameraExposure->value == 0.0f) - { - FBO_FastBlit(srcFbo, srcBox, NULL, dstBox, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - else - { - vec4_t color; - - color[0] = - color[1] = - color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value); - color[3] = 1.0f; - - FBO_Blit(srcFbo, srcBox, NULL, NULL, dstBox, NULL, color, 0); - } - } - - if (r_drawSunRays->integer) - RB_SunRays(NULL, srcBox, NULL, dstBox); - - if (1) - RB_BokehBlur(NULL, srcBox, NULL, dstBox, backEnd.refdef.blurFactor); - else - RB_GaussianBlur(backEnd.refdef.blurFactor); - - if (0 && r_sunlightMode->integer) - { - ivec4_t dstBox; - VectorSet4(dstBox, 0, 0, 128, 128); - FBO_BlitFromTexture(tr.sunShadowDepthImage[0], NULL, NULL, NULL, dstBox, NULL, NULL, 0); - VectorSet4(dstBox, 128, 0, 128, 128); - FBO_BlitFromTexture(tr.sunShadowDepthImage[1], NULL, NULL, NULL, dstBox, NULL, NULL, 0); - VectorSet4(dstBox, 256, 0, 128, 128); - FBO_BlitFromTexture(tr.sunShadowDepthImage[2], NULL, NULL, NULL, dstBox, NULL, NULL, 0); - } - - if (0) - { - ivec4_t dstBox; - VectorSet4(dstBox, 256, glConfig.vidHeight - 256, 256, 256); - FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); - VectorSet4(dstBox, 512, glConfig.vidHeight - 256, 256, 256); - FBO_BlitFromTexture(tr.screenShadowImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); - } - - if (0) - { - ivec4_t dstBox; - VectorSet4(dstBox, 256, glConfig.vidHeight - 256, 256, 256); - FBO_BlitFromTexture(tr.sunRaysImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); - } - -#if 0 - if (r_cubeMapping->integer && tr.numCubemaps) - { - ivec4_t dstBox; - int cubemapIndex = R_CubemapForPoint( backEnd.viewParms.or.origin ); - - if (cubemapIndex) - { - VectorSet4(dstBox, 0, glConfig.vidHeight - 256, 256, 256); - //FBO_BlitFromTexture(tr.renderCubeImage, NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0); - FBO_BlitFromTexture(tr.cubemaps[cubemapIndex - 1], NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0); - } - } -#endif - - backEnd.framePostProcessed = qtrue; - - return (const void *)(cmd + 1); -} - - -/* -==================== -RB_ExecuteRenderCommands -==================== -*/ -void RB_ExecuteRenderCommands( const void *data ) { - int t1, t2; - - t1 = ri.Milliseconds (); - - while ( 1 ) { - data = PADP(data, sizeof(void *)); - - switch ( *(const int *)data ) { - case RC_SET_COLOR: - data = RB_SetColor( data ); - break; - case RC_STRETCH_PIC: - data = RB_StretchPic( data ); - break; - case RC_DRAW_SURFS: - data = RB_DrawSurfs( data ); - break; - case RC_DRAW_BUFFER: - data = RB_DrawBuffer( data ); - break; - case RC_SWAP_BUFFERS: - data = RB_SwapBuffers( data ); - break; - case RC_SCREENSHOT: - data = RB_TakeScreenshotCmd( data ); - break; - case RC_VIDEOFRAME: - data = RB_TakeVideoFrameCmd( data ); - break; - case RC_COLORMASK: - data = RB_ColorMask(data); - break; - case RC_CLEARDEPTH: - data = RB_ClearDepth(data); - break; - case RC_CAPSHADOWMAP: - data = RB_CapShadowMap(data); - break; - case RC_POSTPROCESS: - data = RB_PostProcess(data); - break; - case RC_END_OF_LIST: - default: - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - // stop rendering - t2 = ri.Milliseconds (); - backEnd.pc.msec = t2 - t1; - return; - } - } - -} diff --git a/code/renderergl2/tr_bsp.c b/code/renderergl2/tr_bsp.c deleted file mode 100644 index ba1d21e8fd..0000000000 --- a/code/renderergl2/tr_bsp.c +++ /dev/null @@ -1,3591 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_map.c - -#include "tr_local.h" - -/* - -Loads and prepares a map file for scene rendering. - -A single entry point: - -void RE_LoadWorldMap( const char *name ); - -*/ - -static world_t s_worldData; -static byte *fileBase; - -int c_subdivisions; -int c_gridVerts; - -//=============================================================================== - -static void HSVtoRGB( float h, float s, float v, float rgb[3] ) -{ - int i; - float f; - float p, q, t; - - h *= 5; - - i = floor( h ); - f = h - i; - - p = v * ( 1 - s ); - q = v * ( 1 - s * f ); - t = v * ( 1 - s * ( 1 - f ) ); - - switch ( i ) - { - case 0: - rgb[0] = v; - rgb[1] = t; - rgb[2] = p; - break; - case 1: - rgb[0] = q; - rgb[1] = v; - rgb[2] = p; - break; - case 2: - rgb[0] = p; - rgb[1] = v; - rgb[2] = t; - break; - case 3: - rgb[0] = p; - rgb[1] = q; - rgb[2] = v; - break; - case 4: - rgb[0] = t; - rgb[1] = p; - rgb[2] = v; - break; - case 5: - rgb[0] = v; - rgb[1] = p; - rgb[2] = q; - break; - } -} - -/* -=============== -R_ColorShiftLightingBytes - -=============== -*/ -static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { - int shift, r, g, b; - - // shift the color data based on overbright range - shift = r_mapOverBrightBits->integer - tr.overbrightBits; - - // shift the data based on overbright range - r = in[0] << shift; - g = in[1] << shift; - b = in[2] << shift; - - // normalize by color instead of saturating to white - if ( ( r | g | b ) > 255 ) { - int max; - - max = r > g ? r : g; - max = max > b ? max : b; - r = r * 255 / max; - g = g * 255 / max; - b = b * 255 / max; - } - - out[0] = r; - out[1] = g; - out[2] = b; - out[3] = in[3]; -} - - -/* -=============== -R_ColorShiftLightingFloats - -=============== -*/ -static void R_ColorShiftLightingFloats(float in[4], float out[4], float scale ) -{ - float r, g, b; - - scale *= pow(2.0f, r_mapOverBrightBits->integer - tr.overbrightBits); - - r = in[0] * scale; - g = in[1] * scale; - b = in[2] * scale; - - // normalize by color instead of saturating to white - if ( !r_hdr->integer && ( r > 1 || g > 1 || b > 1 ) ) { - float max; - - max = r > g ? r : g; - max = max > b ? max : b; - r = r / max; - g = g / max; - b = b / max; - } - - out[0] = r; - out[1] = g; - out[2] = b; - out[3] = in[3]; -} - -// Modified from http://graphicrants.blogspot.jp/2009/04/rgbm-color-encoding.html -void ColorToRGBM(const vec3_t color, unsigned char rgbm[4]) -{ - vec3_t sample; - float maxComponent; - - maxComponent = MAX(sample[0], sample[1]); - maxComponent = MAX(maxComponent, sample[2]); - maxComponent = CLAMP(maxComponent, 1.0f/255.0f, 1.0f); - - rgbm[3] = (unsigned char) ceil(maxComponent * 255.0f); - maxComponent = 255.0f / rgbm[3]; - - VectorScale(sample, maxComponent, sample); - - rgbm[0] = (unsigned char) (sample[0] * 255); - rgbm[1] = (unsigned char) (sample[1] * 255); - rgbm[2] = (unsigned char) (sample[2] * 255); -} - -void ColorToRGBA16F(const vec3_t color, unsigned short rgba16f[4]) -{ - rgba16f[0] = FloatToHalf(color[0]); - rgba16f[1] = FloatToHalf(color[1]); - rgba16f[2] = FloatToHalf(color[2]); - rgba16f[3] = FloatToHalf(1.0f); -} - - -/* -=============== -R_LoadLightmaps - -=============== -*/ -#define DEFAULT_LIGHTMAP_SIZE 128 -#define MAX_LIGHTMAP_PAGES 2 -static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { - byte *buf, *buf_p; - dsurface_t *surf; - int len; - byte *image; - int i, j, numLightmaps, textureInternalFormat = 0; - float maxIntensity = 0; - double sumIntensity = 0; - - len = l->filelen; - if ( !len ) { - return; - } - buf = fileBase + l->fileofs; - - // we are about to upload textures - R_IssuePendingRenderCommands(); - - tr.lightmapSize = DEFAULT_LIGHTMAP_SIZE; - numLightmaps = len / (tr.lightmapSize * tr.lightmapSize * 3); - - // check for deluxe mapping - if (numLightmaps <= 1) - { - tr.worldDeluxeMapping = qfalse; - } - else - { - tr.worldDeluxeMapping = qtrue; - for( i = 0, surf = (dsurface_t *)(fileBase + surfs->fileofs); - i < surfs->filelen / sizeof(dsurface_t); i++, surf++ ) { - int lightmapNum = LittleLong( surf->lightmapNum ); - - if ( lightmapNum >= 0 && (lightmapNum & 1) != 0 ) { - tr.worldDeluxeMapping = qfalse; - break; - } - } - } - - image = ri.Malloc(tr.lightmapSize * tr.lightmapSize * 4 * 2); - - if (tr.worldDeluxeMapping) - numLightmaps >>= 1; - - if(numLightmaps == 1) - { - //FIXME: HACK: maps with only one lightmap turn up fullbright for some reason. - //this avoids this, but isn't the correct solution. - numLightmaps++; - } - else if (r_mergeLightmaps->integer && numLightmaps >= 1024 ) - { - // FIXME: fat light maps don't support more than 1024 light maps - ri.Printf(PRINT_WARNING, "WARNING: number of lightmaps > 1024\n"); - numLightmaps = 1024; - } - - // use fat lightmaps of an appropriate size - if (r_mergeLightmaps->integer) - { - tr.fatLightmapSize = 512; - tr.fatLightmapStep = tr.fatLightmapSize / tr.lightmapSize; - - // at most MAX_LIGHTMAP_PAGES - while (tr.fatLightmapStep * tr.fatLightmapStep * MAX_LIGHTMAP_PAGES < numLightmaps && tr.fatLightmapSize != glConfig.maxTextureSize ) - { - tr.fatLightmapSize <<= 1; - tr.fatLightmapStep = tr.fatLightmapSize / tr.lightmapSize; - } - - tr.numLightmaps = numLightmaps / (tr.fatLightmapStep * tr.fatLightmapStep); - - if (numLightmaps % (tr.fatLightmapStep * tr.fatLightmapStep) != 0) - tr.numLightmaps++; - } - else - { - tr.numLightmaps = numLightmaps; - } - - tr.lightmaps = ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low ); - - if (tr.worldDeluxeMapping) - { - tr.deluxemaps = ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low ); - } - - if (r_hdr->integer) - { - if (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer) - textureInternalFormat = GL_RGBA16F_ARB; - else - textureInternalFormat = GL_RGBA8; - } - - if (r_mergeLightmaps->integer) - { - for (i = 0; i < tr.numLightmaps; i++) - { - tr.lightmaps[i] = R_CreateImage(va("_fatlightmap%d", i), NULL, tr.fatLightmapSize, tr.fatLightmapSize, IMGTYPE_COLORALPHA, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, textureInternalFormat ); - - if (tr.worldDeluxeMapping) - { - tr.deluxemaps[i] = R_CreateImage(va("_fatdeluxemap%d", i), NULL, tr.fatLightmapSize, tr.fatLightmapSize, IMGTYPE_DELUXE, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, 0 ); - } - } - } - - for(i = 0; i < numLightmaps; i++) - { - int xoff = 0, yoff = 0; - int lightmapnum = i; - // expand the 24 bit on-disk to 32 bit - - if (r_mergeLightmaps->integer) - { - int lightmaponpage = i % (tr.fatLightmapStep * tr.fatLightmapStep); - xoff = (lightmaponpage % tr.fatLightmapStep) * tr.lightmapSize; - yoff = (lightmaponpage / tr.fatLightmapStep) * tr.lightmapSize; - - lightmapnum /= (tr.fatLightmapStep * tr.fatLightmapStep); - } - - // if (tr.worldLightmapping) - { - char filename[MAX_QPATH]; - byte *hdrLightmap = NULL; - int size = 0; - - // look for hdr lightmaps - if (r_hdr->integer) - { - Com_sprintf( filename, sizeof( filename ), "maps/%s/lm_%04d.hdr", s_worldData.baseName, i * (tr.worldDeluxeMapping ? 2 : 1) ); - //ri.Printf(PRINT_ALL, "looking for %s\n", filename); - - size = ri.FS_ReadFile(filename, (void **)&hdrLightmap); - } - - if (hdrLightmap) - { - byte *p = hdrLightmap; - //ri.Printf(PRINT_ALL, "found!\n"); - - /* FIXME: don't just skip over this header and actually parse it */ - while (size && !(*p == '\n' && *(p+1) == '\n')) - { - size--; - p++; - } - - if (!size) - ri.Error(ERR_DROP, "Bad header for %s!", filename); - - size -= 2; - p += 2; - - while (size && !(*p == '\n')) - { - size--; - p++; - } - - size--; - p++; - - buf_p = (byte *)p; - -#if 0 // HDRFILE_RGBE - if (size != tr.lightmapSize * tr.lightmapSize * 4) - ri.Error(ERR_DROP, "Bad size for %s (%i)!", filename, size); -#else // HDRFILE_FLOAT - if (size != tr.lightmapSize * tr.lightmapSize * 12) - ri.Error(ERR_DROP, "Bad size for %s (%i)!", filename, size); -#endif - } - else - { - if (tr.worldDeluxeMapping) - buf_p = buf + (i * 2) * tr.lightmapSize * tr.lightmapSize * 3; - else - buf_p = buf + i * tr.lightmapSize * tr.lightmapSize * 3; - } - - for ( j = 0 ; j < tr.lightmapSize * tr.lightmapSize; j++ ) - { - if (hdrLightmap) - { - float color[3]; - -#if 0 // HDRFILE_RGBE - float exponent = exp2(buf_p[j*4+3] - 128); - - color[0] = buf_p[j*4+0] * exponent; - color[1] = buf_p[j*4+1] * exponent; - color[2] = buf_p[j*4+2] * exponent; -#else // HDRFILE_FLOAT - memcpy(color, &buf_p[j*12], 12); - - color[0] = LittleFloat(color[0]); - color[1] = LittleFloat(color[1]); - color[2] = LittleFloat(color[2]); -#endif - R_ColorShiftLightingFloats(color, color, 1.0f/255.0f); - - if (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer) - ColorToRGBA16F(color, (unsigned short *)(&image[j*8])); - else - ColorToRGBM(color, &image[j*4]); - } - else if (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer) - { - float color[3]; - - //hack: convert LDR lightmap to HDR one - color[0] = MAX(buf_p[j*3+0], 0.499f); - color[1] = MAX(buf_p[j*3+1], 0.499f); - color[2] = MAX(buf_p[j*3+2], 0.499f); - - // if under an arbitrary value (say 12) grey it out - // this prevents weird splotches in dimly lit areas - if (color[0] + color[1] + color[2] < 12.0f) - { - float avg = (color[0] + color[1] + color[2]) * 0.3333f; - color[0] = avg; - color[1] = avg; - color[2] = avg; - } - - R_ColorShiftLightingFloats(color, color, 1.0f/255.0f); - - ColorToRGBA16F(color, (unsigned short *)(&image[j*8])); - } - else - { - if ( r_lightmap->integer == 2 ) - { // color code by intensity as development tool (FIXME: check range) - float r = buf_p[j*3+0]; - float g = buf_p[j*3+1]; - float b = buf_p[j*3+2]; - float intensity; - float out[3] = {0.0, 0.0, 0.0}; - - intensity = 0.33f * r + 0.685f * g + 0.063f * b; - - if ( intensity > 255 ) - intensity = 1.0f; - else - intensity /= 255.0f; - - if ( intensity > maxIntensity ) - maxIntensity = intensity; - - HSVtoRGB( intensity, 1.00, 0.50, out ); - - image[j*4+0] = out[0] * 255; - image[j*4+1] = out[1] * 255; - image[j*4+2] = out[2] * 255; - image[j*4+3] = 255; - - sumIntensity += intensity; - } - else - { - R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] ); - image[j*4+3] = 255; - } - } - } - - if (r_mergeLightmaps->integer) - R_UpdateSubImage(tr.lightmaps[lightmapnum], image, xoff, yoff, tr.lightmapSize, tr.lightmapSize); - else - tr.lightmaps[i] = R_CreateImage(va("*lightmap%d", i), image, tr.lightmapSize, tr.lightmapSize, IMGTYPE_COLORALPHA, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, textureInternalFormat ); - - if (hdrLightmap) - ri.FS_FreeFile(hdrLightmap); - } - - if (tr.worldDeluxeMapping) - { - buf_p = buf + (i * 2 + 1) * tr.lightmapSize * tr.lightmapSize * 3; - - for ( j = 0 ; j < tr.lightmapSize * tr.lightmapSize; j++ ) { - image[j*4+0] = buf_p[j*3+0]; - image[j*4+1] = buf_p[j*3+1]; - image[j*4+2] = buf_p[j*3+2]; - - // make 0,0,0 into 127,127,127 - if ((image[j*4+0] == 0) && (image[j*4+1] == 0) && (image[j*4+2] == 0)) - { - image[j*4+0] = - image[j*4+1] = - image[j*4+2] = 127; - } - - image[j*4+3] = 255; - } - - if (r_mergeLightmaps->integer) - { - R_UpdateSubImage(tr.deluxemaps[lightmapnum], image, xoff, yoff, tr.lightmapSize, tr.lightmapSize ); - } - else - { - tr.deluxemaps[i] = R_CreateImage(va("*deluxemap%d", i), image, tr.lightmapSize, tr.lightmapSize, IMGTYPE_DELUXE, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, 0 ); - } - } - } - - if ( r_lightmap->integer == 2 ) { - ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) ); - } - - ri.Free(image); -} - - -static float FatPackU(float input, int lightmapnum) -{ - if (lightmapnum < 0) - return input; - - if (tr.worldDeluxeMapping) - lightmapnum >>= 1; - - if(tr.fatLightmapSize > 0) - { - int x; - - lightmapnum %= (tr.fatLightmapStep * tr.fatLightmapStep); - - x = lightmapnum % tr.fatLightmapStep; - - return (input / ((float)tr.fatLightmapStep)) + ((1.0 / ((float)tr.fatLightmapStep)) * (float)x); - } - - return input; -} - -static float FatPackV(float input, int lightmapnum) -{ - if (lightmapnum < 0) - return input; - - if (tr.worldDeluxeMapping) - lightmapnum >>= 1; - - if(tr.fatLightmapSize > 0) - { - int y; - - lightmapnum %= (tr.fatLightmapStep * tr.fatLightmapStep); - - y = lightmapnum / tr.fatLightmapStep; - - return (input / ((float)tr.fatLightmapStep)) + ((1.0 / ((float)tr.fatLightmapStep)) * (float)y); - } - - return input; -} - - -static int FatLightmap(int lightmapnum) -{ - if (lightmapnum < 0) - return lightmapnum; - - if (tr.worldDeluxeMapping) - lightmapnum >>= 1; - - if (tr.fatLightmapSize > 0) - { - return lightmapnum / (tr.fatLightmapStep * tr.fatLightmapStep); - } - - return lightmapnum; -} - -/* -================= -RE_SetWorldVisData - -This is called by the clipmodel subsystem so we can share the 1.8 megs of -space in big maps... -================= -*/ -void RE_SetWorldVisData( const byte *vis ) { - tr.externalVisData = vis; -} - - -/* -================= -R_LoadVisibility -================= -*/ -static void R_LoadVisibility( lump_t *l ) { - int len; - byte *buf; - - len = ( s_worldData.numClusters + 63 ) & ~63; - s_worldData.novis = ri.Hunk_Alloc( len, h_low ); - Com_Memset( s_worldData.novis, 0xff, len ); - - len = l->filelen; - if ( !len ) { - return; - } - buf = fileBase + l->fileofs; - - s_worldData.numClusters = LittleLong( ((int *)buf)[0] ); - s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] ); - - // CM_Load should have given us the vis data to share, so - // we don't need to allocate another copy - if ( tr.externalVisData ) { - s_worldData.vis = tr.externalVisData; - } else { - byte *dest; - - dest = ri.Hunk_Alloc( len - 8, h_low ); - Com_Memcpy( dest, buf + 8, len - 8 ); - s_worldData.vis = dest; - } -} - -//=============================================================================== - - -/* -=============== -ShaderForShaderNum -=============== -*/ -static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) { - shader_t *shader; - dshader_t *dsh; - - int _shaderNum = LittleLong( shaderNum ); - if ( _shaderNum < 0 || _shaderNum >= s_worldData.numShaders ) { - ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", _shaderNum ); - } - dsh = &s_worldData.shaders[ _shaderNum ]; - - if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - lightmapNum = LIGHTMAP_BY_VERTEX; - } - - if ( r_fullbright->integer ) { - lightmapNum = LIGHTMAP_WHITEIMAGE; - } - - shader = R_FindShader( dsh->shader, lightmapNum, qtrue ); - - // if the shader had errors, just use default shader - if ( shader->defaultShader ) { - return tr.defaultShader; - } - - return shader; -} - -/* -=============== -ParseFace -=============== -*/ -static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf, int *indexes ) { - int i, j; - srfBspSurface_t *cv; - glIndex_t *tri; - int numVerts, numIndexes, badTriangles; - int realLightmapNum; - - realLightmapNum = LittleLong( ds->lightmapNum ); - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, FatLightmap(realLightmapNum) ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - numVerts = LittleLong(ds->numVerts); - if (numVerts > MAX_FACE_POINTS) { - ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numVerts); - numVerts = MAX_FACE_POINTS; - surf->shader = tr.defaultShader; - } - - numIndexes = LittleLong(ds->numIndexes); - - //cv = ri.Hunk_Alloc(sizeof(*cv), h_low); - cv = (void *)surf->data; - cv->surfaceType = SF_FACE; - - cv->numIndexes = numIndexes; - cv->indexes = ri.Hunk_Alloc(numIndexes * sizeof(cv->indexes[0]), h_low); - - cv->numVerts = numVerts; - cv->verts = ri.Hunk_Alloc(numVerts * sizeof(cv->verts[0]), h_low); - - // copy vertexes - surf->cullinfo.type = CULLINFO_PLANE | CULLINFO_BOX; - ClearBounds(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]); - verts += LittleLong(ds->firstVert); - for(i = 0; i < numVerts; i++) - { - vec4_t color; - - for(j = 0; j < 3; j++) - { - cv->verts[i].xyz[j] = LittleFloat(verts[i].xyz[j]); - cv->verts[i].normal[j] = LittleFloat(verts[i].normal[j]); - } - AddPointToBounds(cv->verts[i].xyz, surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]); - for(j = 0; j < 2; j++) - { - cv->verts[i].st[j] = LittleFloat(verts[i].st[j]); - //cv->verts[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]); - } - cv->verts[i].lightmap[0] = FatPackU(LittleFloat(verts[i].lightmap[0]), realLightmapNum); - cv->verts[i].lightmap[1] = FatPackV(LittleFloat(verts[i].lightmap[1]), realLightmapNum); - - if (hdrVertColors) - { - color[0] = hdrVertColors[(ds->firstVert + i) * 3 ]; - color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1]; - color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2]; - } - else - { - //hack: convert LDR vertex colors to HDR - if (r_hdr->integer) - { - color[0] = MAX(verts[i].color[0], 0.499f); - color[1] = MAX(verts[i].color[1], 0.499f); - color[2] = MAX(verts[i].color[2], 0.499f); - } - else - { - color[0] = verts[i].color[0]; - color[1] = verts[i].color[1]; - color[2] = verts[i].color[2]; - } - - } - color[3] = verts[i].color[3] / 255.0f; - - R_ColorShiftLightingFloats( color, cv->verts[i].vertexColors, 1.0f / 255.0f ); - } - - // copy triangles - badTriangles = 0; - indexes += LittleLong(ds->firstIndex); - for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) - { - for(j = 0; j < 3; j++) - { - tri[j] = LittleLong(indexes[i + j]); - - if(tri[j] >= numVerts) - { - ri.Error(ERR_DROP, "Bad index in face surface"); - } - } - - if ((tri[0] == tri[1]) || (tri[1] == tri[2]) || (tri[0] == tri[2])) - { - tri -= 3; - badTriangles++; - } - } - - if (badTriangles) - { - ri.Printf(PRINT_WARNING, "Face has bad triangles, originally shader %s %d tris %d verts, now %d tris\n", surf->shader->name, numIndexes / 3, numVerts, numIndexes / 3 - badTriangles); - cv->numIndexes -= badTriangles * 3; - } - - // take the plane information from the lightmap vector - for ( i = 0 ; i < 3 ; i++ ) { - cv->cullPlane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); - } - cv->cullPlane.dist = DotProduct( cv->verts[0].xyz, cv->cullPlane.normal ); - SetPlaneSignbits( &cv->cullPlane ); - cv->cullPlane.type = PlaneTypeForNormal( cv->cullPlane.normal ); - surf->cullinfo.plane = cv->cullPlane; - - surf->data = (surfaceType_t *)cv; - -#ifdef USE_VERT_TANGENT_SPACE - // Calculate tangent spaces - { - srfVert_t *dv[3]; - - for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) - { - dv[0] = &cv->verts[tri[0]]; - dv[1] = &cv->verts[tri[1]]; - dv[2] = &cv->verts[tri[2]]; - - R_CalcTangentVectors(dv); - } - } -#endif -} - - -/* -=============== -ParseMesh -=============== -*/ -static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf ) { - srfBspSurface_t *grid; - int i, j; - int width, height, numPoints; - srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]; - vec3_t bounds[2]; - vec3_t tmpVec; - static surfaceType_t skipData = SF_SKIP; - int realLightmapNum; - - realLightmapNum = LittleLong( ds->lightmapNum ); - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, FatLightmap(realLightmapNum) ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - // we may have a nodraw surface, because they might still need to - // be around for movement clipping - if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) { - surf->data = &skipData; - return; - } - - width = LittleLong( ds->patchWidth ); - height = LittleLong( ds->patchHeight ); - - if(width < 0 || width > MAX_PATCH_SIZE || height < 0 || height > MAX_PATCH_SIZE) - ri.Error(ERR_DROP, "ParseMesh: bad size"); - - verts += LittleLong( ds->firstVert ); - numPoints = width * height; - for(i = 0; i < numPoints; i++) - { - vec4_t color; - - for(j = 0; j < 3; j++) - { - points[i].xyz[j] = LittleFloat(verts[i].xyz[j]); - points[i].normal[j] = LittleFloat(verts[i].normal[j]); - } - - for(j = 0; j < 2; j++) - { - points[i].st[j] = LittleFloat(verts[i].st[j]); - //points[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]); - } - points[i].lightmap[0] = FatPackU(LittleFloat(verts[i].lightmap[0]), realLightmapNum); - points[i].lightmap[1] = FatPackV(LittleFloat(verts[i].lightmap[1]), realLightmapNum); - - if (hdrVertColors) - { - color[0] = hdrVertColors[(ds->firstVert + i) * 3 ]; - color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1]; - color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2]; - } - else - { - //hack: convert LDR vertex colors to HDR - if (r_hdr->integer) - { - color[0] = MAX(verts[i].color[0], 0.499f); - color[1] = MAX(verts[i].color[1], 0.499f); - color[2] = MAX(verts[i].color[2], 0.499f); - } - else - { - color[0] = verts[i].color[0]; - color[1] = verts[i].color[1]; - color[2] = verts[i].color[2]; - } - } - color[3] = verts[i].color[3] / 255.0f; - - R_ColorShiftLightingFloats( color, points[i].vertexColors, 1.0f / 255.0f ); - } - - // pre-tesseleate - grid = R_SubdividePatchToGrid( width, height, points ); - surf->data = (surfaceType_t *)grid; - - // copy the level of detail origin, which is the center - // of the group of all curves that must subdivide the same - // to avoid cracking - for ( i = 0 ; i < 3 ; i++ ) { - bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] ); - bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] ); - } - VectorAdd( bounds[0], bounds[1], bounds[1] ); - VectorScale( bounds[1], 0.5f, grid->lodOrigin ); - VectorSubtract( bounds[0], grid->lodOrigin, tmpVec ); - grid->lodRadius = VectorLength( tmpVec ); -} - -/* -=============== -ParseTriSurf -=============== -*/ -static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf, int *indexes ) { - srfBspSurface_t *cv; - glIndex_t *tri; - int i, j; - int numVerts, numIndexes, badTriangles; - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - numVerts = LittleLong(ds->numVerts); - numIndexes = LittleLong(ds->numIndexes); - - //cv = ri.Hunk_Alloc(sizeof(*cv), h_low); - cv = (void *)surf->data; - cv->surfaceType = SF_TRIANGLES; - - cv->numIndexes = numIndexes; - cv->indexes = ri.Hunk_Alloc(numIndexes * sizeof(cv->indexes[0]), h_low); - - cv->numVerts = numVerts; - cv->verts = ri.Hunk_Alloc(numVerts * sizeof(cv->verts[0]), h_low); - - surf->data = (surfaceType_t *) cv; - - // copy vertexes - surf->cullinfo.type = CULLINFO_BOX; - ClearBounds(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]); - verts += LittleLong(ds->firstVert); - for(i = 0; i < numVerts; i++) - { - vec4_t color; - - for(j = 0; j < 3; j++) - { - cv->verts[i].xyz[j] = LittleFloat(verts[i].xyz[j]); - cv->verts[i].normal[j] = LittleFloat(verts[i].normal[j]); - } - - AddPointToBounds( cv->verts[i].xyz, surf->cullinfo.bounds[0], surf->cullinfo.bounds[1] ); - - for(j = 0; j < 2; j++) - { - cv->verts[i].st[j] = LittleFloat(verts[i].st[j]); - cv->verts[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]); - } - - if (hdrVertColors) - { - color[0] = hdrVertColors[(ds->firstVert + i) * 3 ]; - color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1]; - color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2]; - } - else - { - //hack: convert LDR vertex colors to HDR - if (r_hdr->integer) - { - color[0] = MAX(verts[i].color[0], 0.499f); - color[1] = MAX(verts[i].color[1], 0.499f); - color[2] = MAX(verts[i].color[2], 0.499f); - } - else - { - color[0] = verts[i].color[0]; - color[1] = verts[i].color[1]; - color[2] = verts[i].color[2]; - } - } - color[3] = verts[i].color[3] / 255.0f; - - R_ColorShiftLightingFloats( color, cv->verts[i].vertexColors, 1.0f / 255.0f ); - } - - // copy triangles - badTriangles = 0; - indexes += LittleLong(ds->firstIndex); - for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) - { - for(j = 0; j < 3; j++) - { - tri[j] = LittleLong(indexes[i + j]); - - if(tri[j] >= numVerts) - { - ri.Error(ERR_DROP, "Bad index in face surface"); - } - } - - if ((tri[0] == tri[1]) || (tri[1] == tri[2]) || (tri[0] == tri[2])) - { - tri -= 3; - badTriangles++; - } - } - - if (badTriangles) - { - ri.Printf(PRINT_WARNING, "Trisurf has bad triangles, originally shader %s %d tris %d verts, now %d tris\n", surf->shader->name, numIndexes / 3, numVerts, numIndexes / 3 - badTriangles); - cv->numIndexes -= badTriangles * 3; - } - -#ifdef USE_VERT_TANGENT_SPACE - // Calculate tangent spaces - { - srfVert_t *dv[3]; - - for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) - { - dv[0] = &cv->verts[tri[0]]; - dv[1] = &cv->verts[tri[1]]; - dv[2] = &cv->verts[tri[2]]; - - R_CalcTangentVectors(dv); - } - } -#endif -} - -/* -=============== -ParseFlare -=============== -*/ -static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { - srfFlare_t *flare; - int i; - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - //flare = ri.Hunk_Alloc( sizeof( *flare ), h_low ); - flare = (void *)surf->data; - flare->surfaceType = SF_FLARE; - - surf->data = (surfaceType_t *)flare; - - for ( i = 0 ; i < 3 ; i++ ) { - flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] ); - flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] ); - flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); - } -} - - -/* -================= -R_MergedWidthPoints - -returns true if there are grid points merged on a width edge -================= -*/ -int R_MergedWidthPoints(srfBspSurface_t *grid, int offset) { - int i, j; - - for (i = 1; i < grid->width-1; i++) { - for (j = i + 1; j < grid->width-1; j++) { - if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue; - if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue; - if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue; - return qtrue; - } - } - return qfalse; -} - -/* -================= -R_MergedHeightPoints - -returns true if there are grid points merged on a height edge -================= -*/ -int R_MergedHeightPoints(srfBspSurface_t *grid, int offset) { - int i, j; - - for (i = 1; i < grid->height-1; i++) { - for (j = i + 1; j < grid->height-1; j++) { - if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue; - if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue; - if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue; - return qtrue; - } - } - return qfalse; -} - -/* -================= -R_FixSharedVertexLodError_r - -NOTE: never sync LoD through grid edges with merged points! - -FIXME: write generalized version that also avoids cracks between a patch and one that meets half way? -================= -*/ -void R_FixSharedVertexLodError_r( int start, srfBspSurface_t *grid1 ) { - int j, k, l, m, n, offset1, offset2, touch; - srfBspSurface_t *grid2; - - for ( j = start; j < s_worldData.numsurfaces; j++ ) { - // - grid2 = (srfBspSurface_t *) s_worldData.surfaces[j].data; - // if this surface is not a grid - if ( grid2->surfaceType != SF_GRID ) continue; - // if the LOD errors are already fixed for this patch - if ( grid2->lodFixed == 2 ) continue; - // grids in the same LOD group should have the exact same lod radius - if ( grid1->lodRadius != grid2->lodRadius ) continue; - // grids in the same LOD group should have the exact same lod origin - if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; - if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; - if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; - // - touch = qfalse; - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) continue; - for (k = 1; k < grid1->width-1; k++) { - for (m = 0; m < 2; m++) { - - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - if (R_MergedWidthPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->width-1; l++) { - // - if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->widthLodError[l] = grid1->widthLodError[k]; - touch = qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (m) offset2 = grid2->width-1; - else offset2 = 0; - if (R_MergedHeightPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->height-1; l++) { - // - if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->heightLodError[l] = grid1->widthLodError[k]; - touch = qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) continue; - for (k = 1; k < grid1->height-1; k++) { - for (m = 0; m < 2; m++) { - - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - if (R_MergedWidthPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->width-1; l++) { - // - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->widthLodError[l] = grid1->heightLodError[k]; - touch = qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (m) offset2 = grid2->width-1; - else offset2 = 0; - if (R_MergedHeightPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->height-1; l++) { - // - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->heightLodError[l] = grid1->heightLodError[k]; - touch = qtrue; - } - } - } - } - if (touch) { - grid2->lodFixed = 2; - R_FixSharedVertexLodError_r ( start, grid2 ); - //NOTE: this would be correct but makes things really slow - //grid2->lodFixed = 1; - } - } -} - -/* -================= -R_FixSharedVertexLodError - -This function assumes that all patches in one group are nicely stitched together for the highest LoD. -If this is not the case this function will still do its job but won't fix the highest LoD cracks. -================= -*/ -void R_FixSharedVertexLodError( void ) { - int i; - srfBspSurface_t *grid1; - - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid1 = (srfBspSurface_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid1->surfaceType != SF_GRID ) - continue; - // - if ( grid1->lodFixed ) - continue; - // - grid1->lodFixed = 2; - // recursively fix other patches in the same LOD group - R_FixSharedVertexLodError_r( i + 1, grid1); - } -} - - -/* -=============== -R_StitchPatches -=============== -*/ -int R_StitchPatches( int grid1num, int grid2num ) { - float *v1, *v2; - srfBspSurface_t *grid1, *grid2; - int k, l, m, n, offset1, offset2, row, column; - - grid1 = (srfBspSurface_t *) s_worldData.surfaces[grid1num].data; - grid2 = (srfBspSurface_t *) s_worldData.surfaces[grid2num].data; - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) - continue; - for (k = 0; k < grid1->width-2; k += 2) { - - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k + 2 + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k + 2 + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) - continue; - for (k = 0; k < grid1->height-2; k += 2) { - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) - continue; - for (k = grid1->width-1; k > 1; k -= 2) { - - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k - 2 + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k - 2 + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); - if (!grid2) - break; - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) - continue; - for (k = grid1->height-1; k > 1; k -= 2) { - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - return qfalse; -} - -/* -=============== -R_TryStitchPatch - -This function will try to stitch patches in the same LoD group together for the highest LoD. - -Only single missing vertice cracks will be fixed. - -Vertices will be joined at the patch side a crack is first found, at the other side -of the patch (on the same row or column) the vertices will not be joined and cracks -might still appear at that side. -=============== -*/ -int R_TryStitchingPatch( int grid1num ) { - int j, numstitches; - srfBspSurface_t *grid1, *grid2; - - numstitches = 0; - grid1 = (srfBspSurface_t *) s_worldData.surfaces[grid1num].data; - for ( j = 0; j < s_worldData.numsurfaces; j++ ) { - // - grid2 = (srfBspSurface_t *) s_worldData.surfaces[j].data; - // if this surface is not a grid - if ( grid2->surfaceType != SF_GRID ) continue; - // grids in the same LOD group should have the exact same lod radius - if ( grid1->lodRadius != grid2->lodRadius ) continue; - // grids in the same LOD group should have the exact same lod origin - if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; - if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; - if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; - // - while (R_StitchPatches(grid1num, j)) - { - numstitches++; - } - } - return numstitches; -} - -/* -=============== -R_StitchAllPatches -=============== -*/ -void R_StitchAllPatches( void ) { - int i, stitched, numstitches; - srfBspSurface_t *grid1; - - numstitches = 0; - do - { - stitched = qfalse; - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid1 = (srfBspSurface_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid1->surfaceType != SF_GRID ) - continue; - // - if ( grid1->lodStitched ) - continue; - // - grid1->lodStitched = qtrue; - stitched = qtrue; - // - numstitches += R_TryStitchingPatch( i ); - } - } - while (stitched); - ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches ); -} - -/* -=============== -R_MovePatchSurfacesToHunk -=============== -*/ -void R_MovePatchSurfacesToHunk(void) { - int i, size; - srfBspSurface_t *grid, *hunkgrid; - - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid = (srfBspSurface_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid->surfaceType != SF_GRID ) - continue; - // - size = sizeof(*grid); - hunkgrid = ri.Hunk_Alloc(size, h_low); - Com_Memcpy(hunkgrid, grid, size); - - hunkgrid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_low ); - Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 ); - - hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_low ); - Com_Memcpy( hunkgrid->heightLodError, grid->heightLodError, grid->height * 4 ); - - hunkgrid->numIndexes = grid->numIndexes; - hunkgrid->indexes = ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low); - Com_Memcpy(hunkgrid->indexes, grid->indexes, grid->numIndexes * sizeof(glIndex_t)); - - hunkgrid->numVerts = grid->numVerts; - hunkgrid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low); - Com_Memcpy(hunkgrid->verts, grid->verts, grid->numVerts * sizeof(srfVert_t)); - - R_FreeSurfaceGridMesh( grid ); - - s_worldData.surfaces[i].data = (void *) hunkgrid; - } -} - - -/* -================= -BSPSurfaceCompare -compare function for qsort() -================= -*/ -static int BSPSurfaceCompare(const void *a, const void *b) -{ - msurface_t *aa, *bb; - - aa = *(msurface_t **) a; - bb = *(msurface_t **) b; - - // shader first - if(aa->shader->sortedIndex < bb->shader->sortedIndex) - return -1; - - else if(aa->shader->sortedIndex > bb->shader->sortedIndex) - return 1; - - // by fogIndex - if(aa->fogIndex < bb->fogIndex) - return -1; - - else if(aa->fogIndex > bb->fogIndex) - return 1; - - // by cubemapIndex - if(aa->cubemapIndex < bb->cubemapIndex) - return -1; - - else if(aa->cubemapIndex > bb->cubemapIndex) - return 1; - - - return 0; -} - - -static void CopyVert(const srfVert_t * in, srfVert_t * out) -{ - int j; - - for(j = 0; j < 3; j++) - { - out->xyz[j] = in->xyz[j]; -#ifdef USE_VERT_TANGENT_SPACE - out->tangent[j] = in->tangent[j]; - //out->bitangent[j] = in->bitangent[j]; -#endif - out->normal[j] = in->normal[j]; - out->lightdir[j] = in->lightdir[j]; - } - - out->tangent[3] = in->tangent[3]; - - for(j = 0; j < 2; j++) - { - out->st[j] = in->st[j]; - out->lightmap[j] = in->lightmap[j]; - } - - for(j = 0; j < 4; j++) - { - out->vertexColors[j] = in->vertexColors[j]; - } -} - - -/* -=============== -R_CreateWorldVBOs -=============== -*/ -static void R_CreateWorldVBOs(void) -{ - int i, j, k; - - int numVerts; - srfVert_t *verts; - - int numIndexes; - glIndex_t *indexes; - - int numSortedSurfaces, numSurfaces; - msurface_t *surface, **firstSurf, **lastSurf, **currSurf; - msurface_t **surfacesSorted; - - VBO_t *vbo; - IBO_t *ibo; - - int maxVboSize = 4 * 1024 * 1024; - int maxIboSize = 4 * 1024 * 1024; - - int startTime, endTime; - - startTime = ri.Milliseconds(); - - // count surfaces - numSortedSurfaces = 0; - for(surface = &s_worldData.surfaces[0]; surface < &s_worldData.surfaces[s_worldData.numsurfaces]; surface++) - { - srfBspSurface_t *bspSurf; - shader_t *shader = surface->shader; - - if (shader->isPortal) - continue; - - if (shader->isSky) - continue; - - if (ShaderRequiresCPUDeforms(shader)) - continue; - - // check for this now so we can use srfBspSurface_t* universally in the rest of the function - if (!(*surface->data == SF_FACE || *surface->data == SF_GRID || *surface->data == SF_TRIANGLES)) - continue; - - bspSurf = (srfBspSurface_t *) surface->data; - - if (!bspSurf->numIndexes || !bspSurf->numVerts) - continue; - - numSortedSurfaces++; - } - - // presort surfaces - surfacesSorted = ri.Malloc(numSortedSurfaces * sizeof(*surfacesSorted)); - - j = 0; - for(surface = &s_worldData.surfaces[0]; surface < &s_worldData.surfaces[s_worldData.numsurfaces]; surface++) - { - srfBspSurface_t *bspSurf; - shader_t *shader = surface->shader; - - if (shader->isPortal) - continue; - - if (shader->isSky) - continue; - - if (ShaderRequiresCPUDeforms(shader)) - continue; - - // check for this now so we can use srfBspSurface_t* universally in the rest of the function - if (!(*surface->data == SF_FACE || *surface->data == SF_GRID || *surface->data == SF_TRIANGLES)) - continue; - - bspSurf = (srfBspSurface_t *) surface->data; - - if (!bspSurf->numIndexes || !bspSurf->numVerts) - continue; - - surfacesSorted[j++] = surface; - } - - qsort(surfacesSorted, numSortedSurfaces, sizeof(*surfacesSorted), BSPSurfaceCompare); - - k = 0; - for(firstSurf = lastSurf = surfacesSorted; firstSurf < &surfacesSorted[numSortedSurfaces]; firstSurf = lastSurf) - { - int currVboSize, currIboSize; - - // Find range of surfaces to merge by: - // - Collecting a number of surfaces which fit under maxVboSize/maxIboSize, or - // - All the surfaces with a single shader which go over maxVboSize/maxIboSize - currVboSize = currIboSize = 0; - while (currVboSize < maxVboSize && currIboSize < maxIboSize && lastSurf < &surfacesSorted[numSortedSurfaces]) - { - int addVboSize, addIboSize, currShaderIndex; - - addVboSize = addIboSize = 0; - currShaderIndex = (*lastSurf)->shader->sortedIndex; - - for(currSurf = lastSurf; currSurf < &surfacesSorted[numSortedSurfaces] && (*currSurf)->shader->sortedIndex == currShaderIndex; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - - addVboSize += bspSurf->numVerts * sizeof(srfVert_t); - addIboSize += bspSurf->numIndexes * sizeof(glIndex_t); - } - - if ((currVboSize != 0 && addVboSize + currVboSize > maxVboSize) - || (currIboSize != 0 && addIboSize + currIboSize > maxIboSize)) - break; - - lastSurf = currSurf; - - currVboSize += addVboSize; - currIboSize += addIboSize; - } - - // count verts/indexes/surfaces - numVerts = 0; - numIndexes = 0; - numSurfaces = 0; - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - - numVerts += bspSurf->numVerts; - numIndexes += bspSurf->numIndexes; - numSurfaces++; - } - - ri.Printf(PRINT_ALL, "...calculating world VBO %d ( %i verts %i tris )\n", k, numVerts, numIndexes / 3); - - // create arrays - verts = ri.Hunk_AllocateTempMemory(numVerts * sizeof(srfVert_t)); - indexes = ri.Hunk_AllocateTempMemory(numIndexes * sizeof(glIndex_t)); - - // set up indices and copy vertices - numVerts = 0; - numIndexes = 0; - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - glIndex_t *surfIndex; - - bspSurf->firstIndex = numIndexes; - bspSurf->minIndex = numVerts + bspSurf->indexes[0]; - bspSurf->maxIndex = numVerts + bspSurf->indexes[0]; - - for(i = 0, surfIndex = bspSurf->indexes; i < bspSurf->numIndexes; i++, surfIndex++) - { - indexes[numIndexes++] = numVerts + *surfIndex; - bspSurf->minIndex = MIN(bspSurf->minIndex, numVerts + *surfIndex); - bspSurf->maxIndex = MAX(bspSurf->maxIndex, numVerts + *surfIndex); - } - - bspSurf->firstVert = numVerts; - - for(i = 0; i < bspSurf->numVerts; i++) - { - CopyVert(&bspSurf->verts[i], &verts[numVerts++]); - } - } - -#ifdef USE_VERT_TANGENT_SPACE - vbo = R_CreateVBO2(va("staticBspModel0_VBO %i", k), numVerts, verts, - ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_TANGENT | - ATTR_NORMAL | ATTR_COLOR | ATTR_LIGHTDIRECTION, VBO_USAGE_STATIC); -#else - vbo = R_CreateVBO2(va("staticBspModel0_VBO %i", k), numVerts, verts, - ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | - ATTR_NORMAL | ATTR_COLOR | ATTR_LIGHTDIRECTION, VBO_USAGE_STATIC); -#endif - - ibo = R_CreateIBO2(va("staticBspModel0_IBO %i", k), numIndexes, indexes, VBO_USAGE_STATIC); - - // point bsp surfaces to VBO - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - - bspSurf->vbo = vbo; - bspSurf->ibo = ibo; - } - - ri.Hunk_FreeTempMemory(indexes); - ri.Hunk_FreeTempMemory(verts); - - k++; - } - - ri.Free(surfacesSorted); - - endTime = ri.Milliseconds(); - ri.Printf(PRINT_ALL, "world VBOs calculation time = %5.2f seconds\n", (endTime - startTime) / 1000.0); -} - -/* -=============== -R_LoadSurfaces -=============== -*/ -static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { - dsurface_t *in; - msurface_t *out; - drawVert_t *dv; - int *indexes; - int count; - int numFaces, numMeshes, numTriSurfs, numFlares; - int i; - float *hdrVertColors = NULL; - - numFaces = 0; - numMeshes = 0; - numTriSurfs = 0; - numFlares = 0; - - if (surfs->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = surfs->filelen / sizeof(*in); - - dv = (void *)(fileBase + verts->fileofs); - if (verts->filelen % sizeof(*dv)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - - indexes = (void *)(fileBase + indexLump->fileofs); - if ( indexLump->filelen % sizeof(*indexes)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - - out = ri.Hunk_Alloc ( count * sizeof(*out), h_low ); - - s_worldData.surfaces = out; - s_worldData.numsurfaces = count; - s_worldData.surfacesViewCount = ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesViewCount), h_low ); - s_worldData.surfacesDlightBits = ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesDlightBits), h_low ); - s_worldData.surfacesPshadowBits = ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesPshadowBits), h_low ); - - // load hdr vertex colors - if (r_hdr->integer) - { - char filename[MAX_QPATH]; - int size; - - Com_sprintf( filename, sizeof( filename ), "maps/%s/vertlight.raw", s_worldData.baseName); - //ri.Printf(PRINT_ALL, "looking for %s\n", filename); - - size = ri.FS_ReadFile(filename, (void **)&hdrVertColors); - - if (hdrVertColors) - { - //ri.Printf(PRINT_ALL, "Found!\n"); - if (size != sizeof(float) * 3 * (verts->filelen / sizeof(*dv))) - ri.Error(ERR_DROP, "Bad size for %s (%i, expected %i)!", filename, size, (int)((sizeof(float)) * 3 * (verts->filelen / sizeof(*dv)))); - } - } - - - // Two passes, allocate surfaces first, then load them full of data - // This ensures surfaces are close together to reduce L2 cache misses when using VBOs, - // which don't actually use the verts and indexes - in = (void *)(fileBase + surfs->fileofs); - out = s_worldData.surfaces; - for ( i = 0 ; i < count ; i++, in++, out++ ) { - switch ( LittleLong( in->surfaceType ) ) { - case MST_PATCH: - // FIXME: do this - break; - case MST_TRIANGLE_SOUP: - out->data = ri.Hunk_Alloc( sizeof(srfBspSurface_t), h_low); - break; - case MST_PLANAR: - out->data = ri.Hunk_Alloc( sizeof(srfBspSurface_t), h_low); - break; - case MST_FLARE: - out->data = ri.Hunk_Alloc( sizeof(srfFlare_t), h_low); - break; - default: - break; - } - } - - in = (void *)(fileBase + surfs->fileofs); - out = s_worldData.surfaces; - for ( i = 0 ; i < count ; i++, in++, out++ ) { - switch ( LittleLong( in->surfaceType ) ) { - case MST_PATCH: - ParseMesh ( in, dv, hdrVertColors, out ); - { - srfBspSurface_t *surface = (srfBspSurface_t *)out->data; - - out->cullinfo.type = CULLINFO_BOX | CULLINFO_SPHERE; - VectorCopy(surface->cullBounds[0], out->cullinfo.bounds[0]); - VectorCopy(surface->cullBounds[1], out->cullinfo.bounds[1]); - VectorCopy(surface->cullOrigin, out->cullinfo.localOrigin); - out->cullinfo.radius = surface->cullRadius; - } - numMeshes++; - break; - case MST_TRIANGLE_SOUP: - ParseTriSurf( in, dv, hdrVertColors, out, indexes ); - numTriSurfs++; - break; - case MST_PLANAR: - ParseFace( in, dv, hdrVertColors, out, indexes ); - numFaces++; - break; - case MST_FLARE: - ParseFlare( in, dv, out, indexes ); - { - out->cullinfo.type = CULLINFO_NONE; - } - numFlares++; - break; - default: - ri.Error( ERR_DROP, "Bad surfaceType" ); - } - } - - if (hdrVertColors) - { - ri.FS_FreeFile(hdrVertColors); - } - -#ifdef PATCH_STITCHING - R_StitchAllPatches(); -#endif - - R_FixSharedVertexLodError(); - -#ifdef PATCH_STITCHING - R_MovePatchSurfacesToHunk(); -#endif - - ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", - numFaces, numMeshes, numTriSurfs, numFlares ); -} - - - -/* -================= -R_LoadSubmodels -================= -*/ -static void R_LoadSubmodels( lump_t *l ) { - dmodel_t *in; - bmodel_t *out; - int i, j, count; - - in = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - - s_worldData.numBModels = count; - s_worldData.bmodels = out = ri.Hunk_Alloc( count * sizeof(*out), h_low ); - - for ( i=0 ; itype = MOD_BRUSH; - model->bmodel = out; - Com_sprintf( model->name, sizeof( model->name ), "*%d", i ); - - for (j=0 ; j<3 ; j++) { - out->bounds[0][j] = LittleFloat (in->mins[j]); - out->bounds[1][j] = LittleFloat (in->maxs[j]); - } - - out->firstSurface = LittleLong( in->firstSurface ); - out->numSurfaces = LittleLong( in->numSurfaces ); - - if(i == 0) - { - // Add this for limiting VBO surface creation - s_worldData.numWorldSurfaces = out->numSurfaces; - } - } -} - - - -//================================================================== - -/* -================= -R_SetParent -================= -*/ -static void R_SetParent (mnode_t *node, mnode_t *parent) -{ - node->parent = parent; - if (node->contents != -1) - return; - R_SetParent (node->children[0], node); - R_SetParent (node->children[1], node); -} - -/* -================= -R_LoadNodesAndLeafs -================= -*/ -static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) { - int i, j, p; - dnode_t *in; - dleaf_t *inLeaf; - mnode_t *out; - int numNodes, numLeafs; - - in = (void *)(fileBase + nodeLump->fileofs); - if (nodeLump->filelen % sizeof(dnode_t) || - leafLump->filelen % sizeof(dleaf_t) ) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - numNodes = nodeLump->filelen / sizeof(dnode_t); - numLeafs = leafLump->filelen / sizeof(dleaf_t); - - out = ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low); - - s_worldData.nodes = out; - s_worldData.numnodes = numNodes + numLeafs; - s_worldData.numDecisionNodes = numNodes; - - // load nodes - for ( i=0 ; imins[j] = LittleLong (in->mins[j]); - out->maxs[j] = LittleLong (in->maxs[j]); - } - - p = LittleLong(in->planeNum); - out->plane = s_worldData.planes + p; - - out->contents = CONTENTS_NODE; // differentiate from leafs - - for (j=0 ; j<2 ; j++) - { - p = LittleLong (in->children[j]); - if (p >= 0) - out->children[j] = s_worldData.nodes + p; - else - out->children[j] = s_worldData.nodes + numNodes + (-1 - p); - } - } - - // load leafs - inLeaf = (void *)(fileBase + leafLump->fileofs); - for ( i=0 ; imins[j] = LittleLong (inLeaf->mins[j]); - out->maxs[j] = LittleLong (inLeaf->maxs[j]); - } - - out->cluster = LittleLong(inLeaf->cluster); - out->area = LittleLong(inLeaf->area); - - if ( out->cluster >= s_worldData.numClusters ) { - s_worldData.numClusters = out->cluster + 1; - } - - out->firstmarksurface = LittleLong(inLeaf->firstLeafSurface); - out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces); - } - - // chain decendants - R_SetParent (s_worldData.nodes, NULL); -} - -//============================================================================= - -/* -================= -R_LoadShaders -================= -*/ -static void R_LoadShaders( lump_t *l ) { - int i, count; - dshader_t *in, *out; - - in = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*sizeof(*out), h_low ); - - s_worldData.shaders = out; - s_worldData.numShaders = count; - - Com_Memcpy( out, in, count*sizeof(*out) ); - - for ( i=0 ; ifileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*sizeof(*out), h_low); - - s_worldData.marksurfaces = out; - s_worldData.nummarksurfaces = count; - - for ( i=0 ; ifileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*2*sizeof(*out), h_low); - - s_worldData.planes = out; - s_worldData.numplanes = count; - - for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); - if (out->normal[j] < 0) { - bits |= 1<dist = LittleFloat (in->dist); - out->type = PlaneTypeForNormal( out->normal ); - out->signbits = bits; - } -} - -/* -================= -R_LoadFogs - -================= -*/ -static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) { - int i; - fog_t *out; - dfog_t *fogs; - dbrush_t *brushes, *brush; - dbrushside_t *sides; - int count, brushesCount, sidesCount; - int sideNum; - int planeNum; - shader_t *shader; - float d; - int firstSide; - - fogs = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*fogs)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - count = l->filelen / sizeof(*fogs); - - // create fog strucutres for them - s_worldData.numfogs = count + 1; - s_worldData.fogs = ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low); - out = s_worldData.fogs + 1; - - if ( !count ) { - return; - } - - brushes = (void *)(fileBase + brushesLump->fileofs); - if (brushesLump->filelen % sizeof(*brushes)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - brushesCount = brushesLump->filelen / sizeof(*brushes); - - sides = (void *)(fileBase + sidesLump->fileofs); - if (sidesLump->filelen % sizeof(*sides)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - sidesCount = sidesLump->filelen / sizeof(*sides); - - for ( i=0 ; ioriginalBrushNumber = LittleLong( fogs->brushNum ); - - if ( (unsigned)out->originalBrushNumber >= brushesCount ) { - ri.Error( ERR_DROP, "fog brushNumber out of range" ); - } - brush = brushes + out->originalBrushNumber; - - firstSide = LittleLong( brush->firstSide ); - - if ( (unsigned)firstSide > sidesCount - 6 ) { - ri.Error( ERR_DROP, "fog brush sideNumber out of range" ); - } - - // brushes are always sorted with the axial sides first - sideNum = firstSide + 0; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 1; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][0] = s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 2; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 3; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][1] = s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 4; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 5; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][2] = s_worldData.planes[ planeNum ].dist; - - // get information from the shader for fog parameters - shader = R_FindShader( fogs->shader, LIGHTMAP_NONE, qtrue ); - - out->parms = shader->fogParms; - - out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight, - shader->fogParms.color[1] * tr.identityLight, - shader->fogParms.color[2] * tr.identityLight, 1.0 ); - - d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque; - out->tcScale = 1.0f / ( d * 8 ); - - // set the gradient vector - sideNum = LittleLong( fogs->visibleSide ); - - if ( sideNum == -1 ) { - out->hasSurface = qfalse; - } else { - out->hasSurface = qtrue; - planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum ); - VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface ); - out->surface[3] = -s_worldData.planes[ planeNum ].dist; - } - - out++; - } - -} - - -/* -================ -R_LoadLightGrid - -================ -*/ -void R_LoadLightGrid( lump_t *l ) { - int i; - vec3_t maxs; - int numGridPoints; - world_t *w; - float *wMins, *wMaxs; - - w = &s_worldData; - - w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0]; - w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1]; - w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2]; - - wMins = w->bmodels[0].bounds[0]; - wMaxs = w->bmodels[0].bounds[1]; - - for ( i = 0 ; i < 3 ; i++ ) { - w->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] ); - maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] ); - w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1; - } - - numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2]; - - if ( l->filelen != numGridPoints * 8 ) { - ri.Printf( PRINT_WARNING, "WARNING: light grid mismatch\n" ); - w->lightGridData = NULL; - return; - } - - w->lightGridData = ri.Hunk_Alloc( l->filelen, h_low ); - Com_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen ); - - // deal with overbright bits - for ( i = 0 ; i < numGridPoints ; i++ ) { - R_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] ); - R_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] ); - } - - // load hdr lightgrid - if (r_hdr->integer) - { - char filename[MAX_QPATH]; - float *hdrLightGrid; - int size; - - Com_sprintf( filename, sizeof( filename ), "maps/%s/lightgrid.raw", s_worldData.baseName); - //ri.Printf(PRINT_ALL, "looking for %s\n", filename); - - size = ri.FS_ReadFile(filename, (void **)&hdrLightGrid); - - if (hdrLightGrid) - { - float lightScale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits); - - //ri.Printf(PRINT_ALL, "found!\n"); - - if (size != sizeof(float) * 6 * numGridPoints) - { - ri.Error(ERR_DROP, "Bad size for %s (%i, expected %i)!", filename, size, (int)(sizeof(float)) * 6 * numGridPoints); - } - - w->hdrLightGrid = ri.Hunk_Alloc(size, h_low); - - for (i = 0; i < numGridPoints ; i++) - { - w->hdrLightGrid[i * 6 ] = hdrLightGrid[i * 6 ] * lightScale; - w->hdrLightGrid[i * 6 + 1] = hdrLightGrid[i * 6 + 1] * lightScale; - w->hdrLightGrid[i * 6 + 2] = hdrLightGrid[i * 6 + 2] * lightScale; - w->hdrLightGrid[i * 6 + 3] = hdrLightGrid[i * 6 + 3] * lightScale; - w->hdrLightGrid[i * 6 + 4] = hdrLightGrid[i * 6 + 4] * lightScale; - w->hdrLightGrid[i * 6 + 5] = hdrLightGrid[i * 6 + 5] * lightScale; - } - } - - if (hdrLightGrid) - ri.FS_FreeFile(hdrLightGrid); - } -} - -/* -================ -R_LoadEntities -================ -*/ -void R_LoadEntities( lump_t *l ) { - char *p, *token, *s; - char keyname[MAX_TOKEN_CHARS]; - char value[MAX_TOKEN_CHARS]; - world_t *w; - - w = &s_worldData; - w->lightGridSize[0] = 64; - w->lightGridSize[1] = 64; - w->lightGridSize[2] = 128; - - p = (char *)(fileBase + l->fileofs); - - // store for reference by the cgame - w->entityString = ri.Hunk_Alloc( l->filelen + 1, h_low ); - strcpy( w->entityString, p ); - w->entityParsePoint = w->entityString; - - token = COM_ParseExt( &p, qtrue ); - if (!*token || *token != '{') { - return; - } - - // only parse the world spawn - while ( 1 ) { - // parse key - token = COM_ParseExt( &p, qtrue ); - - if ( !*token || *token == '}' ) { - break; - } - Q_strncpyz(keyname, token, sizeof(keyname)); - - // parse value - token = COM_ParseExt( &p, qtrue ); - - if ( !*token || *token == '}' ) { - break; - } - Q_strncpyz(value, token, sizeof(value)); - - // check for remapping of shaders for vertex lighting - s = "vertexremapshader"; - if (!Q_strncmp(keyname, s, strlen(s)) ) { - s = strchr(value, ';'); - if (!s) { - ri.Printf( PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value ); - break; - } - *s++ = 0; - if (r_vertexLight->integer) { - R_RemapShader(value, s, "0"); - } - continue; - } - // check for remapping of shaders - s = "remapshader"; - if (!Q_strncmp(keyname, s, strlen(s)) ) { - s = strchr(value, ';'); - if (!s) { - ri.Printf( PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value ); - break; - } - *s++ = 0; - R_RemapShader(value, s, "0"); - continue; - } - // check for a different grid size - if (!Q_stricmp(keyname, "gridsize")) { - sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] ); - continue; - } - - // check for auto exposure - if (!Q_stricmp(keyname, "autoExposureMinMax")) { - sscanf(value, "%f %f", &tr.autoExposureMinMax[0], &tr.autoExposureMinMax[1]); - continue; - } - } -} - -/* -================= -R_GetEntityToken -================= -*/ -qboolean R_GetEntityToken( char *buffer, int size ) { - const char *s; - - s = COM_Parse( &s_worldData.entityParsePoint ); - Q_strncpyz( buffer, s, size ); - if ( !s_worldData.entityParsePoint || !s[0] ) { - s_worldData.entityParsePoint = s_worldData.entityString; - return qfalse; - } else { - return qtrue; - } -} - -#ifndef MAX_SPAWN_VARS -#define MAX_SPAWN_VARS 64 -#endif - -// derived from G_ParseSpawnVars() in g_spawn.c -qboolean R_ParseSpawnVars( char *spawnVarChars, int maxSpawnVarChars, int *numSpawnVars, char *spawnVars[MAX_SPAWN_VARS][2] ) -{ - char keyname[MAX_TOKEN_CHARS]; - char com_token[MAX_TOKEN_CHARS]; - int numSpawnVarChars = 0; - - *numSpawnVars = 0; - - // parse the opening brace - if ( !R_GetEntityToken( com_token, sizeof( com_token ) ) ) { - // end of spawn string - return qfalse; - } - if ( com_token[0] != '{' ) { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: found %s when expecting {",com_token ); - } - - // go through all the key / value pairs - while ( 1 ) { - int keyLength, tokenLength; - - // parse key - if ( !R_GetEntityToken( keyname, sizeof( keyname ) ) ) { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: EOF without closing brace" ); - } - - if ( keyname[0] == '}' ) { - break; - } - - // parse value - if ( !R_GetEntityToken( com_token, sizeof( com_token ) ) ) { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: EOF without closing brace" ); - break; - } - - if ( com_token[0] == '}' ) { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: closing brace without data" ); - break; - } - - if ( *numSpawnVars == MAX_SPAWN_VARS ) { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: MAX_SPAWN_VARS" ); - break; - } - - keyLength = strlen(keyname) + 1; - tokenLength = strlen(com_token) + 1; - - if (numSpawnVarChars + keyLength + tokenLength > maxSpawnVarChars) - { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: MAX_SPAWN_VAR_CHARS" ); - break; - } - - strcpy(spawnVarChars + numSpawnVarChars, keyname); - spawnVars[ *numSpawnVars ][0] = spawnVarChars + numSpawnVarChars; - numSpawnVarChars += keyLength; - - strcpy(spawnVarChars + numSpawnVarChars, com_token); - spawnVars[ *numSpawnVars ][1] = spawnVarChars + numSpawnVarChars; - numSpawnVarChars += tokenLength; - - (*numSpawnVars)++; - } - - return qtrue; -} - -void R_LoadCubemapEntities(char *cubemapEntityName) -{ - char spawnVarChars[2048]; - int numSpawnVars; - char *spawnVars[MAX_SPAWN_VARS][2]; - int numCubemaps = 0; - - // count cubemaps - numCubemaps = 0; - while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars)) - { - int i; - - for (i = 0; i < numSpawnVars; i++) - { - if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName)) - numCubemaps++; - } - } - - if (!numCubemaps) - return; - - tr.numCubemaps = numCubemaps; - tr.cubemapOrigins = ri.Hunk_Alloc( tr.numCubemaps * sizeof(*tr.cubemapOrigins), h_low); - tr.cubemaps = ri.Hunk_Alloc( tr.numCubemaps * sizeof(*tr.cubemaps), h_low); - - numCubemaps = 0; - while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars)) - { - int i; - qboolean isCubemap = qfalse; - qboolean positionSet = qfalse; - vec3_t origin; - - for (i = 0; i < numSpawnVars; i++) - { - if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName)) - isCubemap = qtrue; - - if (!Q_stricmp(spawnVars[i][0], "origin")) - { - sscanf(spawnVars[i][1], "%f %f %f", &origin[0], &origin[1], &origin[2]); - positionSet = qtrue; - } - } - - if (isCubemap && positionSet) - { - //ri.Printf(PRINT_ALL, "cubemap at %f %f %f\n", origin[0], origin[1], origin[2]); - VectorCopy(origin, tr.cubemapOrigins[numCubemaps]); - numCubemaps++; - } - } -} - -void R_AssignCubemapsToWorldSurfaces(void) -{ - world_t *w; - int i; - - w = &s_worldData; - - for (i = 0; i < w->numsurfaces; i++) - { - msurface_t *surf = &w->surfaces[i]; - vec3_t surfOrigin; - - if (surf->cullinfo.type & CULLINFO_SPHERE) - { - VectorCopy(surf->cullinfo.localOrigin, surfOrigin); - } - else if (surf->cullinfo.type & CULLINFO_BOX) - { - surfOrigin[0] = (surf->cullinfo.bounds[0][0] + surf->cullinfo.bounds[1][0]) * 0.5f; - surfOrigin[1] = (surf->cullinfo.bounds[0][1] + surf->cullinfo.bounds[1][1]) * 0.5f; - surfOrigin[2] = (surf->cullinfo.bounds[0][2] + surf->cullinfo.bounds[1][2]) * 0.5f; - } - else - { - //ri.Printf(PRINT_ALL, "surface %d has no cubemap\n", i); - continue; - } - - surf->cubemapIndex = R_CubemapForPoint(surfOrigin); - //ri.Printf(PRINT_ALL, "surface %d has cubemap %d\n", i, surf->cubemapIndex); - } -} - - -void R_RenderAllCubemaps(void) -{ - int i, j; - - for (i = 0; i < tr.numCubemaps; i++) - { - tr.cubemaps[i] = R_CreateImage(va("*cubeMap%d", i), NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, GL_RGBA8); - } - - for (i = 0; i < tr.numCubemaps; i++) - { - for (j = 0; j < 6; j++) - { - RE_ClearScene(); - R_RenderCubemapSide(i, j, qfalse); - R_IssuePendingRenderCommands(); - R_InitNextFrame(); - } - } -} - - -/* -================= -R_MergeLeafSurfaces - -Merges surfaces that share a common leaf -================= -*/ -void R_MergeLeafSurfaces(void) -{ - int i, j, k; - int numWorldSurfaces; - int mergedSurfIndex; - int numMergedSurfaces; - int numUnmergedSurfaces; - VBO_t *vbo; - IBO_t *ibo; - - msurface_t *mergedSurf; - - glIndex_t *iboIndexes, *outIboIndexes; - int numIboIndexes; - - int startTime, endTime; - - startTime = ri.Milliseconds(); - - numWorldSurfaces = s_worldData.numWorldSurfaces; - - // use viewcount to keep track of mergers - for (i = 0; i < numWorldSurfaces; i++) - { - s_worldData.surfacesViewCount[i] = -1; - } - - // mark matching surfaces - for (i = 0; i < s_worldData.numnodes - s_worldData.numDecisionNodes; i++) - { - mnode_t *leaf = s_worldData.nodes + s_worldData.numDecisionNodes + i; - - for (j = 0; j < leaf->nummarksurfaces; j++) - { - msurface_t *surf1; - shader_t *shader1; - int fogIndex1; - int cubemapIndex1; - int surfNum1; - - surfNum1 = *(s_worldData.marksurfaces + leaf->firstmarksurface + j); - - if (s_worldData.surfacesViewCount[surfNum1] != -1) - continue; - - surf1 = s_worldData.surfaces + surfNum1; - - if ((*surf1->data != SF_GRID) && (*surf1->data != SF_TRIANGLES) && (*surf1->data != SF_FACE)) - continue; - - shader1 = surf1->shader; - - if(shader1->isSky) - continue; - - if(shader1->isPortal) - continue; - - if(ShaderRequiresCPUDeforms(shader1)) - continue; - - fogIndex1 = surf1->fogIndex; - cubemapIndex1 = surf1->cubemapIndex; - - s_worldData.surfacesViewCount[surfNum1] = surfNum1; - - for (k = j + 1; k < leaf->nummarksurfaces; k++) - { - msurface_t *surf2; - shader_t *shader2; - int fogIndex2; - int cubemapIndex2; - int surfNum2; - - surfNum2 = *(s_worldData.marksurfaces + leaf->firstmarksurface + k); - - if (s_worldData.surfacesViewCount[surfNum2] != -1) - continue; - - surf2 = s_worldData.surfaces + surfNum2; - - if ((*surf2->data != SF_GRID) && (*surf2->data != SF_TRIANGLES) && (*surf2->data != SF_FACE)) - continue; - - shader2 = surf2->shader; - - if (shader1 != shader2) - continue; - - fogIndex2 = surf2->fogIndex; - - if (fogIndex1 != fogIndex2) - continue; - - cubemapIndex2 = surf2->cubemapIndex; - - if (cubemapIndex1 != cubemapIndex2) - continue; - - s_worldData.surfacesViewCount[surfNum2] = surfNum1; - } - } - } - - // don't add surfaces that don't merge to any others to the merged list - for (i = 0; i < numWorldSurfaces; i++) - { - qboolean merges = qfalse; - - if (s_worldData.surfacesViewCount[i] != i) - continue; - - for (j = 0; j < numWorldSurfaces; j++) - { - if (j == i) - continue; - - if (s_worldData.surfacesViewCount[j] == i) - { - merges = qtrue; - break; - } - } - - if (!merges) - s_worldData.surfacesViewCount[i] = -1; - } - - // count merged/unmerged surfaces - numMergedSurfaces = 0; - numUnmergedSurfaces = 0; - for (i = 0; i < numWorldSurfaces; i++) - { - if (s_worldData.surfacesViewCount[i] == i) - { - numMergedSurfaces++; - } - else if (s_worldData.surfacesViewCount[i] == -1) - { - numUnmergedSurfaces++; - } - } - - // Allocate merged surfaces - s_worldData.mergedSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfaces) * numMergedSurfaces, h_low); - s_worldData.mergedSurfacesViewCount = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesViewCount) * numMergedSurfaces, h_low); - s_worldData.mergedSurfacesDlightBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesDlightBits) * numMergedSurfaces, h_low); - s_worldData.mergedSurfacesPshadowBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesPshadowBits) * numMergedSurfaces, h_low); - s_worldData.numMergedSurfaces = numMergedSurfaces; - - // view surfaces are like mark surfaces, except negative ones represent merged surfaces - // -1 represents 0, -2 represents 1, and so on - s_worldData.viewSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.viewSurfaces) * s_worldData.nummarksurfaces, h_low); - - // copy view surfaces into mark surfaces - for (i = 0; i < s_worldData.nummarksurfaces; i++) - { - s_worldData.viewSurfaces[i] = s_worldData.marksurfaces[i]; - } - - // need to be synched here - R_IssuePendingRenderCommands(); - - // actually merge surfaces - numIboIndexes = 0; - mergedSurfIndex = 0; - mergedSurf = s_worldData.mergedSurfaces; - for (i = 0; i < numWorldSurfaces; i++) - { - msurface_t *surf1; - - vec3_t bounds[2]; - - int numSurfsToMerge; - int numIndexes; - int numVerts; - int firstIndex; - - srfBspSurface_t *vboSurf; - - if (s_worldData.surfacesViewCount[i] != i) - continue; - - surf1 = s_worldData.surfaces + i; - - // retrieve vbo - vbo = ((srfBspSurface_t *)(surf1->data))->vbo; - - // count verts, indexes, and surfaces - numSurfsToMerge = 0; - numIndexes = 0; - numVerts = 0; - for (j = i; j < numWorldSurfaces; j++) - { - msurface_t *surf2; - srfBspSurface_t *bspSurf; - - if (s_worldData.surfacesViewCount[j] != i) - continue; - - surf2 = s_worldData.surfaces + j; - - bspSurf = (srfBspSurface_t *) surf2->data; - numIndexes += bspSurf->numIndexes; - numVerts += bspSurf->numVerts; - numSurfsToMerge++; - } - - if (numVerts == 0 || numIndexes == 0 || numSurfsToMerge < 2) - { - continue; - } - - // create ibo - ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); - memset(ibo, 0, sizeof(*ibo)); - Q_strncpyz(ibo->name, va("staticWorldMesh_IBO_mergedSurfs%i", tr.numIBOs++), sizeof(ibo->name)); - numIboIndexes = 0; - - // allocate indexes - iboIndexes = outIboIndexes = ri.Malloc(numIndexes * sizeof(*outIboIndexes)); - - // Merge surfaces (indexes) and calculate bounds - ClearBounds(bounds[0], bounds[1]); - firstIndex = numIboIndexes; - for (j = i; j < numWorldSurfaces; j++) - { - msurface_t *surf2; - srfBspSurface_t *bspSurf; - - if (s_worldData.surfacesViewCount[j] != i) - continue; - - surf2 = s_worldData.surfaces + j; - - AddPointToBounds(surf2->cullinfo.bounds[0], bounds[0], bounds[1]); - AddPointToBounds(surf2->cullinfo.bounds[1], bounds[0], bounds[1]); - - bspSurf = (srfBspSurface_t *) surf2->data; - for (k = 0; k < bspSurf->numIndexes; k++) - { - *outIboIndexes++ = bspSurf->indexes[k] + bspSurf->firstVert; - numIboIndexes++; - } - break; - } - - vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low); - memset(vboSurf, 0, sizeof(*vboSurf)); - vboSurf->surfaceType = SF_VBO_MESH; - - vboSurf->vbo = vbo; - vboSurf->ibo = ibo; - - vboSurf->numIndexes = numIndexes; - vboSurf->numVerts = numVerts; - vboSurf->firstIndex = firstIndex; - - vboSurf->minIndex = *(iboIndexes + firstIndex); - vboSurf->maxIndex = *(iboIndexes + firstIndex); - - for (j = 0; j < numIndexes; j++) - { - vboSurf->minIndex = MIN(vboSurf->minIndex, *(iboIndexes + firstIndex + j)); - vboSurf->maxIndex = MAX(vboSurf->maxIndex, *(iboIndexes + firstIndex + j)); - } - - VectorCopy(bounds[0], vboSurf->cullBounds[0]); - VectorCopy(bounds[1], vboSurf->cullBounds[1]); - - VectorCopy(bounds[0], mergedSurf->cullinfo.bounds[0]); - VectorCopy(bounds[1], mergedSurf->cullinfo.bounds[1]); - - mergedSurf->cullinfo.type = CULLINFO_BOX; - mergedSurf->data = (surfaceType_t *)vboSurf; - mergedSurf->fogIndex = surf1->fogIndex; - mergedSurf->cubemapIndex = surf1->cubemapIndex; - mergedSurf->shader = surf1->shader; - - // finish up the ibo - qglGenBuffersARB(1, &ibo->indexesVBO); - - R_BindIBO(ibo); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, numIboIndexes * sizeof(*iboIndexes), iboIndexes, GL_STATIC_DRAW_ARB); - R_BindNullIBO(); - - GL_CheckErrors(); - - ri.Free(iboIndexes); - - // redirect view surfaces to this surf - for (j = 0; j < numWorldSurfaces; j++) - { - if (s_worldData.surfacesViewCount[j] != i) - continue; - - for (k = 0; k < s_worldData.nummarksurfaces; k++) - { - int *mark = s_worldData.marksurfaces + k; - int *view = s_worldData.viewSurfaces + k; - - if (*mark == j) - *view = -(mergedSurfIndex + 1); - } - } - - mergedSurfIndex++; - mergedSurf++; - } - - endTime = ri.Milliseconds(); - - ri.Printf(PRINT_ALL, "Processed %d surfaces into %d merged, %d unmerged in %5.2f seconds\n", - numWorldSurfaces, numMergedSurfaces, numUnmergedSurfaces, (endTime - startTime) / 1000.0f); - - // reset viewcounts - for (i = 0; i < numWorldSurfaces; i++) - { - s_worldData.surfacesViewCount[i] = -1; - } -} - - -void R_CalcVertexLightDirs( void ) -{ - int i, k; - msurface_t *surface; - - for(k = 0, surface = &s_worldData.surfaces[0]; k < s_worldData.numsurfaces /* s_worldData.numWorldSurfaces */; k++, surface++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) surface->data; - - switch(bspSurf->surfaceType) - { - case SF_FACE: - case SF_GRID: - case SF_TRIANGLES: - for(i = 0; i < bspSurf->numVerts; i++) - R_LightDirForPoint( bspSurf->verts[i].xyz, bspSurf->verts[i].lightdir, bspSurf->verts[i].normal, &s_worldData ); - - break; - - default: - break; - } - } -} - - -/* -================= -RE_LoadWorldMap - -Called directly from cgame -================= -*/ -void RE_LoadWorldMap( const char *name ) { - int i; - dheader_t *header; - union { - byte *b; - void *v; - } buffer; - byte *startMarker; - - if ( tr.worldMapLoaded ) { - ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map" ); - } - - // set default map light scale - tr.mapLightScale = 1.0f; - tr.sunShadowScale = 0.5f; - - // set default sun direction to be used if it isn't - // overridden by a shader - tr.sunDirection[0] = 0.45f; - tr.sunDirection[1] = 0.3f; - tr.sunDirection[2] = 0.9f; - - VectorNormalize( tr.sunDirection ); - - // set default autoexposure settings - tr.autoExposureMinMax[0] = -2.0f; - tr.autoExposureMinMax[1] = 2.0f; - - // set default tone mapping settings - tr.toneMinAvgMaxLevel[0] = -8.0f; - tr.toneMinAvgMaxLevel[1] = -2.0f; - tr.toneMinAvgMaxLevel[2] = 0.0f; - - tr.worldMapLoaded = qtrue; - - // load it - ri.FS_ReadFile( name, &buffer.v ); - if ( !buffer.b ) { - ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name); - } - - // clear tr.world so if the level fails to load, the next - // try will not look at the partially loaded version - tr.world = NULL; - - Com_Memset( &s_worldData, 0, sizeof( s_worldData ) ); - Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) ); - - Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) ); - COM_StripExtension(s_worldData.baseName, s_worldData.baseName, sizeof(s_worldData.baseName)); - - startMarker = ri.Hunk_Alloc(0, h_low); - c_gridVerts = 0; - - header = (dheader_t *)buffer.b; - fileBase = (byte *)header; - - i = LittleLong (header->version); - if ( i != BSP_VERSION ) { - ri.Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)", - name, i, BSP_VERSION); - } - - // swap all the lumps - for (i=0 ; ilumps[LUMP_ENTITIES] ); - R_LoadShaders( &header->lumps[LUMP_SHADERS] ); - R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS], &header->lumps[LUMP_SURFACES] ); - R_LoadPlanes (&header->lumps[LUMP_PLANES]); - R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] ); - R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] ); - R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]); - R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]); - R_LoadSubmodels (&header->lumps[LUMP_MODELS]); - R_LoadVisibility( &header->lumps[LUMP_VISIBILITY] ); - R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] ); - - // determine vertex light directions - R_CalcVertexLightDirs(); - - // determine which parts of the map are in sunlight - if (0) - { - world_t *w; - uint8_t *primaryLightGrid, *data; - int lightGridSize; - int i; - - w = &s_worldData; - - lightGridSize = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2]; - primaryLightGrid = ri.Malloc(lightGridSize * sizeof(*primaryLightGrid)); - - memset(primaryLightGrid, 0, lightGridSize * sizeof(*primaryLightGrid)); - - data = w->lightGridData; - for (i = 0; i < lightGridSize; i++, data += 8) - { - int lat, lng; - vec3_t gridLightDir, gridLightCol; - - // skip samples in wall - if (!(data[0]+data[1]+data[2]+data[3]+data[4]+data[5]) ) - continue; - - gridLightCol[0] = ByteToFloat(data[3]); - gridLightCol[1] = ByteToFloat(data[4]); - gridLightCol[2] = ByteToFloat(data[5]); - (void)gridLightCol; // Suppress unused-but-set-variable warning - - lat = data[7]; - lng = data[6]; - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - gridLightDir[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - gridLightDir[1] = tr.sinTable[lat] * tr.sinTable[lng]; - gridLightDir[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - // FIXME: magic number for determining if light direction is close enough to sunlight - if (DotProduct(gridLightDir, tr.sunDirection) > 0.75f) - { - primaryLightGrid[i] = 1; - } - else - { - primaryLightGrid[i] = 255; - } - } - - if (0) - { - int i; - byte *buffer = ri.Malloc(w->lightGridBounds[0] * w->lightGridBounds[1] * 3 + 18); - byte *out; - uint8_t *in; - char fileName[MAX_QPATH]; - - Com_Memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = w->lightGridBounds[0] & 255; - buffer[13] = w->lightGridBounds[0] >> 8; - buffer[14] = w->lightGridBounds[1] & 255; - buffer[15] = w->lightGridBounds[1] >> 8; - buffer[16] = 24; // pixel size - - in = primaryLightGrid; - for (i = 0; i < w->lightGridBounds[2]; i++) - { - int j; - - sprintf(fileName, "primarylg%d.tga", i); - - out = buffer + 18; - for (j = 0; j < w->lightGridBounds[0] * w->lightGridBounds[1]; j++) - { - if (*in == 1) - { - *out++ = 255; - *out++ = 255; - *out++ = 255; - } - else if (*in == 255) - { - *out++ = 64; - *out++ = 64; - *out++ = 64; - } - else - { - *out++ = 0; - *out++ = 0; - *out++ = 0; - } - in++; - } - - ri.FS_WriteFile(fileName, buffer, w->lightGridBounds[0] * w->lightGridBounds[1] * 3 + 18); - } - - ri.Free(buffer); - } - - for (i = 0; i < w->numWorldSurfaces; i++) - { - msurface_t *surf = w->surfaces + i; - cullinfo_t *ci = &surf->cullinfo; - - if(ci->type & CULLINFO_PLANE) - { - if (DotProduct(ci->plane.normal, tr.sunDirection) <= 0.0f) - { - //ri.Printf(PRINT_ALL, "surface %d is not oriented towards sunlight\n", i); - continue; - } - } - - if(ci->type & CULLINFO_BOX) - { - int ibounds[2][3], x, y, z, goodSamples, numSamples; - vec3_t lightOrigin; - - VectorSubtract( ci->bounds[0], w->lightGridOrigin, lightOrigin ); - - ibounds[0][0] = floor(lightOrigin[0] * w->lightGridInverseSize[0]); - ibounds[0][1] = floor(lightOrigin[1] * w->lightGridInverseSize[1]); - ibounds[0][2] = floor(lightOrigin[2] * w->lightGridInverseSize[2]); - - VectorSubtract( ci->bounds[1], w->lightGridOrigin, lightOrigin ); - - ibounds[1][0] = ceil(lightOrigin[0] * w->lightGridInverseSize[0]); - ibounds[1][1] = ceil(lightOrigin[1] * w->lightGridInverseSize[1]); - ibounds[1][2] = ceil(lightOrigin[2] * w->lightGridInverseSize[2]); - - ibounds[0][0] = CLAMP(ibounds[0][0], 0, w->lightGridSize[0]); - ibounds[0][1] = CLAMP(ibounds[0][1], 0, w->lightGridSize[1]); - ibounds[0][2] = CLAMP(ibounds[0][2], 0, w->lightGridSize[2]); - - ibounds[1][0] = CLAMP(ibounds[1][0], 0, w->lightGridSize[0]); - ibounds[1][1] = CLAMP(ibounds[1][1], 0, w->lightGridSize[1]); - ibounds[1][2] = CLAMP(ibounds[1][2], 0, w->lightGridSize[2]); - - /* - ri.Printf(PRINT_ALL, "surf %d bounds (%f %f %f)-(%f %f %f) ibounds (%d %d %d)-(%d %d %d)\n", i, - ci->bounds[0][0], ci->bounds[0][1], ci->bounds[0][2], - ci->bounds[1][0], ci->bounds[1][1], ci->bounds[1][2], - ibounds[0][0], ibounds[0][1], ibounds[0][2], - ibounds[1][0], ibounds[1][1], ibounds[1][2]); - */ - - goodSamples = 0; - numSamples = 0; - for (x = ibounds[0][0]; x <= ibounds[1][0]; x++) - { - for (y = ibounds[0][1]; y <= ibounds[1][1]; y++) - { - for (z = ibounds[0][2]; z <= ibounds[1][2]; z++) - { - uint8_t primaryLight = primaryLightGrid[x * 8 + y * 8 * w->lightGridBounds[0] + z * 8 * w->lightGridBounds[0] * w->lightGridBounds[2]]; - - if (primaryLight == 0) - continue; - - numSamples++; - - if (primaryLight == 1) - goodSamples++; - } - } - } - - // FIXME: magic number for determining whether object is mostly in sunlight - if (goodSamples > numSamples * 0.75f) - { - //ri.Printf(PRINT_ALL, "surface %d is in sunlight\n", i); - //surf->primaryLight = 1; - } - } - } - - ri.Free(primaryLightGrid); - } - - // load cubemaps - if (r_cubeMapping->integer) - { - R_LoadCubemapEntities("misc_cubemap"); - if (!tr.numCubemaps) - { - // use deathmatch spawn points as cubemaps - R_LoadCubemapEntities("info_player_deathmatch"); - } - - if (tr.numCubemaps) - { - R_AssignCubemapsToWorldSurfaces(); - } - } - - // create static VBOS from the world - R_CreateWorldVBOs(); - if (r_mergeLeafSurfaces->integer) - { - R_MergeLeafSurfaces(); - } - - s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker; - - // only set tr.world now that we know the entire level has loaded properly - tr.world = &s_worldData; - - // make sure the VBO glState entries are safe - R_BindNullVBO(); - R_BindNullIBO(); - - // Render all cubemaps - if (r_cubeMapping->integer && tr.numCubemaps) - { - R_RenderAllCubemaps(); - } - - ri.FS_FreeFile( buffer.v ); -} diff --git a/code/renderergl2/tr_cmds.c b/code/renderergl2/tr_cmds.c deleted file mode 100644 index 139a34302d..0000000000 --- a/code/renderergl2/tr_cmds.c +++ /dev/null @@ -1,575 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -/* -===================== -R_PerformanceCounters -===================== -*/ -void R_PerformanceCounters( void ) { - if ( !r_speeds->integer ) { - // clear the counters even if we aren't printing - Com_Memset( &tr.pc, 0, sizeof( tr.pc ) ); - Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); - return; - } - - if (r_speeds->integer == 1) { - ri.Printf (PRINT_ALL, "%i/%i/%i shaders/batches/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n", - backEnd.pc.c_shaders, backEnd.pc.c_surfBatches, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes, - backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3, - R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) ); - } else if (r_speeds->integer == 2) { - ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", - tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out, - tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out ); - ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", - tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out, - tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out ); - } else if (r_speeds->integer == 3) { - ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster ); - } else if (r_speeds->integer == 4) { - if ( backEnd.pc.c_dlightVertexes ) { - ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n", - tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled, - backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 ); - } - } - else if (r_speeds->integer == 5 ) - { - ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar ); - } - else if (r_speeds->integer == 6 ) - { - ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n", - backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders ); - } - else if (r_speeds->integer == 7 ) - { - ri.Printf( PRINT_ALL, "VBO draws: static %i dynamic %i\nMultidraws: %i merged %i\n", - backEnd.pc.c_staticVboDraws, backEnd.pc.c_dynamicVboDraws, backEnd.pc.c_multidraws, backEnd.pc.c_multidrawsMerged ); - ri.Printf( PRINT_ALL, "GLSL binds: %i draws: gen %i light %i fog %i dlight %i\n", - backEnd.pc.c_glslShaderBinds, backEnd.pc.c_genericDraws, backEnd.pc.c_lightallDraws, backEnd.pc.c_fogDraws, backEnd.pc.c_dlightDraws); - } - - Com_Memset( &tr.pc, 0, sizeof( tr.pc ) ); - Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); -} - - -/* -==================== -R_IssueRenderCommands -==================== -*/ -void R_IssueRenderCommands( qboolean runPerformanceCounters ) { - renderCommandList_t *cmdList; - - cmdList = &backEndData->commands; - assert(cmdList); - // add an end-of-list command - *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST; - - // clear it out, in case this is a sync and not a buffer flip - cmdList->used = 0; - - if ( runPerformanceCounters ) { - R_PerformanceCounters(); - } - - // actually start the commands going - if ( !r_skipBackEnd->integer ) { - // let it start on the new batch - RB_ExecuteRenderCommands( cmdList->cmds ); - } -} - - -/* -==================== -R_IssuePendingRenderCommands - -Issue any pending commands and wait for them to complete. -==================== -*/ -void R_IssuePendingRenderCommands( void ) { - if ( !tr.registered ) { - return; - } - R_IssueRenderCommands( qfalse ); -} - -/* -============ -R_GetCommandBuffer - -make sure there is enough command space -============ -*/ -void *R_GetCommandBuffer( int bytes ) { - renderCommandList_t *cmdList; - - cmdList = &backEndData->commands; - bytes = PAD(bytes, sizeof(void *)); - - // always leave room for the end of list command - if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) { - if ( bytes > MAX_RENDER_COMMANDS - 4 ) { - ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes ); - } - // if we run out of room, just start dropping commands - return NULL; - } - - cmdList->used += bytes; - - return cmdList->cmds + cmdList->used - bytes; -} - - -/* -============= -R_AddDrawSurfCmd - -============= -*/ -void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) { - drawSurfsCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_DRAW_SURFS; - - cmd->drawSurfs = drawSurfs; - cmd->numDrawSurfs = numDrawSurfs; - - cmd->refdef = tr.refdef; - cmd->viewParms = tr.viewParms; -} - - -/* -============= -R_AddCapShadowmapCmd - -============= -*/ -void R_AddCapShadowmapCmd( int map, int cubeSide ) { - capShadowmapCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_CAPSHADOWMAP; - - cmd->map = map; - cmd->cubeSide = cubeSide; -} - - -/* -============= -R_PostProcessingCmd - -============= -*/ -void R_AddPostProcessCmd( ) { - postProcessCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_POSTPROCESS; - - cmd->refdef = tr.refdef; - cmd->viewParms = tr.viewParms; -} - -/* -============= -RE_SetColor - -Passing NULL will set the color to white -============= -*/ -void RE_SetColor( const float *rgba ) { - setColorCommand_t *cmd; - - if ( !tr.registered ) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SET_COLOR; - if ( !rgba ) { - static float colorWhite[4] = { 1, 1, 1, 1 }; - - rgba = colorWhite; - } - - cmd->color[0] = rgba[0]; - cmd->color[1] = rgba[1]; - cmd->color[2] = rgba[2]; - cmd->color[3] = rgba[3]; -} - - -/* -============= -RE_StretchPic -============= -*/ -void RE_StretchPic ( float x, float y, float w, float h, - float s1, float t1, float s2, float t2, qhandle_t hShader ) { - stretchPicCommand_t *cmd; - - if (!tr.registered) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_STRETCH_PIC; - cmd->shader = R_GetShaderByHandle( hShader ); - cmd->x = x; - cmd->y = y; - cmd->w = w; - cmd->h = h; - cmd->s1 = s1; - cmd->t1 = t1; - cmd->s2 = s2; - cmd->t2 = t2; -} - -#define MODE_RED_CYAN 1 -#define MODE_RED_BLUE 2 -#define MODE_RED_GREEN 3 -#define MODE_GREEN_MAGENTA 4 -#define MODE_MAX MODE_GREEN_MAGENTA - -void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode) -{ - rgba[0] = rgba[1] = rgba[2] = rgba[3] = GL_TRUE; - - if(colormode > MODE_MAX) - { - if(stereoFrame == STEREO_LEFT) - stereoFrame = STEREO_RIGHT; - else if(stereoFrame == STEREO_RIGHT) - stereoFrame = STEREO_LEFT; - - colormode -= MODE_MAX; - } - - if(colormode == MODE_GREEN_MAGENTA) - { - if(stereoFrame == STEREO_LEFT) - rgba[0] = rgba[2] = GL_FALSE; - else if(stereoFrame == STEREO_RIGHT) - rgba[1] = GL_FALSE; - } - else - { - if(stereoFrame == STEREO_LEFT) - rgba[1] = rgba[2] = GL_FALSE; - else if(stereoFrame == STEREO_RIGHT) - { - rgba[0] = GL_FALSE; - - if(colormode == MODE_RED_BLUE) - rgba[1] = GL_FALSE; - else if(colormode == MODE_RED_GREEN) - rgba[2] = GL_FALSE; - } - } -} - - -/* -==================== -RE_BeginFrame - -If running in stereo, RE_BeginFrame will be called twice -for each RE_EndFrame -==================== -*/ -void RE_BeginFrame( stereoFrame_t stereoFrame ) { - drawBufferCommand_t *cmd = NULL; - colorMaskCommand_t *colcmd = NULL; - - if ( !tr.registered ) { - return; - } - glState.finishCalled = qfalse; - - tr.frameCount++; - tr.frameSceneNum = 0; - - // - // do overdraw measurement - // - if ( r_measureOverdraw->integer ) - { - if ( glConfig.stencilBits < 4 ) - { - ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits ); - ri.Cvar_Set( "r_measureOverdraw", "0" ); - r_measureOverdraw->modified = qfalse; - } - else if ( r_shadows->integer == 2 ) - { - ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" ); - ri.Cvar_Set( "r_measureOverdraw", "0" ); - r_measureOverdraw->modified = qfalse; - } - else - { - R_IssuePendingRenderCommands(); - qglEnable( GL_STENCIL_TEST ); - qglStencilMask( ~0U ); - qglClearStencil( 0U ); - qglStencilFunc( GL_ALWAYS, 0U, ~0U ); - qglStencilOp( GL_KEEP, GL_INCR, GL_INCR ); - } - r_measureOverdraw->modified = qfalse; - } - else - { - // this is only reached if it was on and is now off - if ( r_measureOverdraw->modified ) { - R_IssuePendingRenderCommands(); - qglDisable( GL_STENCIL_TEST ); - } - r_measureOverdraw->modified = qfalse; - } - - // - // texturemode stuff - // - if ( r_textureMode->modified ) { - R_IssuePendingRenderCommands(); - GL_TextureMode( r_textureMode->string ); - r_textureMode->modified = qfalse; - } - - // - // gamma stuff - // - if ( r_gamma->modified ) { - r_gamma->modified = qfalse; - - R_IssuePendingRenderCommands(); - R_SetColorMappings(); - } - - // check for errors - if ( !r_ignoreGLErrors->integer ) - { - int err; - - R_IssuePendingRenderCommands(); - if ((err = qglGetError()) != GL_NO_ERROR) - ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err); - } - - if (glConfig.stereoEnabled) { - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - - cmd->commandId = RC_DRAW_BUFFER; - - if ( stereoFrame == STEREO_LEFT ) { - cmd->buffer = (int)GL_BACK_LEFT; - } else if ( stereoFrame == STEREO_RIGHT ) { - cmd->buffer = (int)GL_BACK_RIGHT; - } else { - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame ); - } - } - else - { - if(r_anaglyphMode->integer) - { - if(r_anaglyphMode->modified) - { - // clear both, front and backbuffer. - qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - backEnd.colorMask[0] = GL_FALSE; - backEnd.colorMask[1] = GL_FALSE; - backEnd.colorMask[2] = GL_FALSE; - backEnd.colorMask[3] = GL_FALSE; - qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); - - if (glRefConfig.framebufferObject) - { - // clear all framebuffers - if (tr.msaaResolveFbo) - { - FBO_Bind(tr.msaaResolveFbo); - qglClear(GL_COLOR_BUFFER_BIT); - } - - if (tr.renderFbo) - { - FBO_Bind(tr.renderFbo); - qglClear(GL_COLOR_BUFFER_BIT); - } - - FBO_Bind(NULL); - } - - qglDrawBuffer(GL_FRONT); - qglClear(GL_COLOR_BUFFER_BIT); - qglDrawBuffer(GL_BACK); - qglClear(GL_COLOR_BUFFER_BIT); - - r_anaglyphMode->modified = qfalse; - } - - if(stereoFrame == STEREO_LEFT) - { - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - - if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) ) - return; - } - else if(stereoFrame == STEREO_RIGHT) - { - clearDepthCommand_t *cldcmd; - - if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) ) - return; - - cldcmd->commandId = RC_CLEARDEPTH; - - if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) ) - return; - } - else - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame ); - - R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer); - colcmd->commandId = RC_COLORMASK; - } - else - { - if(stereoFrame != STEREO_CENTER) - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame ); - - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - } - - if(cmd) - { - cmd->commandId = RC_DRAW_BUFFER; - - if(r_anaglyphMode->modified) - { - qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - backEnd.colorMask[0] = 0; - backEnd.colorMask[1] = 0; - backEnd.colorMask[2] = 0; - backEnd.colorMask[3] = 0; - r_anaglyphMode->modified = qfalse; - } - - if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT")) - cmd->buffer = (int)GL_FRONT; - else - cmd->buffer = (int)GL_BACK; - } - } - - tr.refdef.stereoFrame = stereoFrame; -} - - -/* -============= -RE_EndFrame - -Returns the number of msec spent in the back end -============= -*/ -void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) { - swapBuffersCommand_t *cmd; - - if ( !tr.registered ) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SWAP_BUFFERS; - - R_IssueRenderCommands( qtrue ); - - R_InitNextFrame(); - - if ( frontEndMsec ) { - *frontEndMsec = tr.frontEndMsec; - } - tr.frontEndMsec = 0; - if ( backEndMsec ) { - *backEndMsec = backEnd.pc.msec; - } - backEnd.pc.msec = 0; -} - -/* -============= -RE_TakeVideoFrame -============= -*/ -void RE_TakeVideoFrame( int width, int height, - byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ) -{ - videoFrameCommand_t *cmd; - - if( !tr.registered ) { - return; - } - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if( !cmd ) { - return; - } - - cmd->commandId = RC_VIDEOFRAME; - - cmd->width = width; - cmd->height = height; - cmd->captureBuffer = captureBuffer; - cmd->encodeBuffer = encodeBuffer; - cmd->motionJpeg = motionJpeg; -} diff --git a/code/renderergl2/tr_curve.c b/code/renderergl2/tr_curve.c deleted file mode 100644 index 91c80a4d19..0000000000 --- a/code/renderergl2/tr_curve.c +++ /dev/null @@ -1,761 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -/* - -This file does all of the processing necessary to turn a raw grid of points -read from the map file into a srfBspSurface_t ready for rendering. - -The level of detail solution is direction independent, based only on subdivided -distance from the true curve. - -Only a single entry point: - -srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, - srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { - -*/ - - -/* -============ -LerpDrawVert -============ -*/ -static void LerpDrawVert( srfVert_t *a, srfVert_t *b, srfVert_t *out ) { - out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]); - out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]); - out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]); - - out->st[0] = 0.5f * (a->st[0] + b->st[0]); - out->st[1] = 0.5f * (a->st[1] + b->st[1]); - - out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]); - out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]); - - out->vertexColors[0] = 0.5f * (a->vertexColors[0] + b->vertexColors[0]); - out->vertexColors[1] = 0.5f * (a->vertexColors[1] + b->vertexColors[1]); - out->vertexColors[2] = 0.5f * (a->vertexColors[2] + b->vertexColors[2]); - out->vertexColors[3] = 0.5f * (a->vertexColors[3] + b->vertexColors[3]); -} - -/* -============ -Transpose -============ -*/ -static void Transpose( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j; - srfVert_t temp; - - if ( width > height ) { - for ( i = 0 ; i < height ; i++ ) { - for ( j = i + 1 ; j < width ; j++ ) { - if ( j < height ) { - // swap the value - temp = ctrl[j][i]; - ctrl[j][i] = ctrl[i][j]; - ctrl[i][j] = temp; - } else { - // just copy - ctrl[j][i] = ctrl[i][j]; - } - } - } - } else { - for ( i = 0 ; i < width ; i++ ) { - for ( j = i + 1 ; j < height ; j++ ) { - if ( j < width ) { - // swap the value - temp = ctrl[i][j]; - ctrl[i][j] = ctrl[j][i]; - ctrl[j][i] = temp; - } else { - // just copy - ctrl[i][j] = ctrl[j][i]; - } - } - } - } - -} - - -/* -================= -MakeMeshNormals - -Handles all the complicated wrapping and degenerate cases -================= -*/ -static void MakeMeshNormals( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j, k, dist; - vec3_t normal; - vec3_t sum; - int count = 0; - vec3_t base; - vec3_t delta; - int x, y; - srfVert_t *dv; - vec3_t around[8], temp; - qboolean good[8]; - qboolean wrapWidth, wrapHeight; - float len; -static int neighbors[8][2] = { - {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} - }; - - wrapWidth = qfalse; - for ( i = 0 ; i < height ; i++ ) { - VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta ); - len = VectorLengthSquared( delta ); - if ( len > 1.0 ) { - break; - } - } - if ( i == height ) { - wrapWidth = qtrue; - } - - wrapHeight = qfalse; - for ( i = 0 ; i < width ; i++ ) { - VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta ); - len = VectorLengthSquared( delta ); - if ( len > 1.0 ) { - break; - } - } - if ( i == width) { - wrapHeight = qtrue; - } - - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - count = 0; - dv = &ctrl[j][i]; - VectorCopy( dv->xyz, base ); - for ( k = 0 ; k < 8 ; k++ ) { - VectorClear( around[k] ); - good[k] = qfalse; - - for ( dist = 1 ; dist <= 3 ; dist++ ) { - x = i + neighbors[k][0] * dist; - y = j + neighbors[k][1] * dist; - if ( wrapWidth ) { - if ( x < 0 ) { - x = width - 1 + x; - } else if ( x >= width ) { - x = 1 + x - width; - } - } - if ( wrapHeight ) { - if ( y < 0 ) { - y = height - 1 + y; - } else if ( y >= height ) { - y = 1 + y - height; - } - } - - if ( x < 0 || x >= width || y < 0 || y >= height ) { - break; // edge of patch - } - VectorSubtract( ctrl[y][x].xyz, base, temp ); - if ( VectorNormalize2( temp, temp ) == 0 ) { - continue; // degenerate edge, get more dist - } else { - good[k] = qtrue; - VectorCopy( temp, around[k] ); - break; // good edge - } - } - } - - VectorClear( sum ); - for ( k = 0 ; k < 8 ; k++ ) { - if ( !good[k] || !good[(k+1)&7] ) { - continue; // didn't get two points - } - CrossProduct( around[(k+1)&7], around[k], normal ); - if ( VectorNormalize2( normal, normal ) == 0 ) { - continue; - } - VectorAdd( normal, sum, sum ); - count++; - } - //if ( count == 0 ) { - // printf("bad normal\n"); - //} - VectorNormalize2( sum, dv->normal ); - } - } -} - -#ifdef USE_VERT_TANGENT_SPACE -static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int numIndexes, - glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) -{ - int i, j; - srfVert_t *dv[3]; - static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE]; - glIndex_t *tri; - - // FIXME: use more elegant way - for(i = 0; i < width; i++) - { - for(j = 0; j < height; j++) - { - dv[0] = &ctrl2[j * width + i]; - *dv[0] = ctrl[j][i]; - } - } - - for(i = 0, tri = indexes; i < numIndexes; i += 3, tri += 3) - { - dv[0] = &ctrl2[tri[0]]; - dv[1] = &ctrl2[tri[1]]; - dv[2] = &ctrl2[tri[2]]; - - R_CalcTangentVectors(dv); - } - - for(i = 0; i < width; i++) - { - for(j = 0; j < height; j++) - { - dv[0] = &ctrl2[j * width + i]; - dv[1] = &ctrl[j][i]; - - VectorCopy4(dv[0]->tangent, dv[1]->tangent); - } - } -} -#endif - - -static int MakeMeshIndexes(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], - glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) -{ - int i, j; - int numIndexes; - int w, h; - srfVert_t *dv; - static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE]; - - h = height - 1; - w = width - 1; - numIndexes = 0; - for(i = 0; i < h; i++) - { - for(j = 0; j < w; j++) - { - int v1, v2, v3, v4; - - // vertex order to be reckognized as tristrips - v1 = i * width + j + 1; - v2 = v1 - 1; - v3 = v2 + width; - v4 = v3 + 1; - - indexes[numIndexes++] = v2; - indexes[numIndexes++] = v3; - indexes[numIndexes++] = v1; - - indexes[numIndexes++] = v1; - indexes[numIndexes++] = v3; - indexes[numIndexes++] = v4; - } - } - - // FIXME: use more elegant way - for(i = 0; i < width; i++) - { - for(j = 0; j < height; j++) - { - dv = &ctrl2[j * width + i]; - *dv = ctrl[j][i]; - } - } - - return numIndexes; -} - - -/* -============ -InvertCtrl -============ -*/ -static void InvertCtrl( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j; - srfVert_t temp; - - for ( i = 0 ; i < height ; i++ ) { - for ( j = 0 ; j < width/2 ; j++ ) { - temp = ctrl[i][j]; - ctrl[i][j] = ctrl[i][width-1-j]; - ctrl[i][width-1-j] = temp; - } - } -} - - -/* -================= -InvertErrorTable -================= -*/ -static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) { - int i; - float copy[2][MAX_GRID_SIZE]; - - Com_Memcpy( copy, errorTable, sizeof( copy ) ); - - for ( i = 0 ; i < width ; i++ ) { - errorTable[1][i] = copy[0][i]; //[width-1-i]; - } - - for ( i = 0 ; i < height ; i++ ) { - errorTable[0][i] = copy[1][height-1-i]; - } - -} - -/* -================== -PutPointsOnCurve -================== -*/ -static void PutPointsOnCurve( srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], - int width, int height ) { - int i, j; - srfVert_t prev, next; - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 1 ; j < height ; j += 2 ) { - LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev ); - LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next ); - LerpDrawVert( &prev, &next, &ctrl[j][i] ); - } - } - - - for ( j = 0 ; j < height ; j++ ) { - for ( i = 1 ; i < width ; i += 2 ) { - LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev ); - LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next ); - LerpDrawVert( &prev, &next, &ctrl[j][i] ); - } - } -} - -/* -================= -R_CreateSurfaceGridMesh -================= -*/ -srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height, - srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE], - int numIndexes, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) { - int i, j, size; - srfVert_t *vert; - vec3_t tmpVec; - srfBspSurface_t *grid; - - // copy the results out to a grid - size = (width * height - 1) * sizeof( srfVert_t ) + sizeof( *grid ); - -#ifdef PATCH_STITCHING - grid = /*ri.Hunk_Alloc*/ ri.Malloc( size ); - Com_Memset(grid, 0, size); - - grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 ); - Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); - - grid->heightLodError = /*ri.Hunk_Alloc*/ ri.Malloc( height * 4 ); - Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); - - grid->numIndexes = numIndexes; - grid->indexes = ri.Malloc(grid->numIndexes * sizeof(glIndex_t)); - Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t)); - - grid->numVerts = (width * height); - grid->verts = ri.Malloc(grid->numVerts * sizeof(srfVert_t)); -#else - grid = ri.Hunk_Alloc( size ); - Com_Memset(grid, 0, size); - - grid->widthLodError = ri.Hunk_Alloc( width * 4 ); - Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); - - grid->heightLodError = ri.Hunk_Alloc( height * 4 ); - Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); - - grid->numIndexes = numIndexes; - grid->indexes = ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low); - Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t)); - - grid->numVerts = (width * height); - grid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low); -#endif - - grid->width = width; - grid->height = height; - grid->surfaceType = SF_GRID; - ClearBounds( grid->cullBounds[0], grid->cullBounds[1] ); - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - vert = &grid->verts[j*width+i]; - *vert = ctrl[j][i]; - AddPointToBounds( vert->xyz, grid->cullBounds[0], grid->cullBounds[1] ); - } - } - - // compute local origin and bounds - VectorAdd( grid->cullBounds[0], grid->cullBounds[1], grid->cullOrigin ); - VectorScale( grid->cullOrigin, 0.5f, grid->cullOrigin ); - VectorSubtract( grid->cullBounds[0], grid->cullOrigin, tmpVec ); - grid->cullRadius = VectorLength( tmpVec ); - - VectorCopy( grid->cullOrigin, grid->lodOrigin ); - grid->lodRadius = grid->cullRadius; - // - return grid; -} - -/* -================= -R_FreeSurfaceGridMesh -================= -*/ -void R_FreeSurfaceGridMesh( srfBspSurface_t *grid ) { - ri.Free(grid->widthLodError); - ri.Free(grid->heightLodError); - ri.Free(grid->indexes); - ri.Free(grid->verts); - ri.Free(grid); -} - -/* -================= -R_SubdividePatchToGrid -================= -*/ -srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, - srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { - int i, j, k, l; - srfVert_t_cleared( prev ); - srfVert_t_cleared( next ); - srfVert_t_cleared( mid ); - float len, maxLen; - int dir; - int t; - srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - int numIndexes; - static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]; - int consecutiveComplete; - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - ctrl[j][i] = points[j*width+i]; - } - } - - for ( dir = 0 ; dir < 2 ; dir++ ) { - - for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) { - errorTable[dir][j] = 0; - } - - consecutiveComplete = 0; - - // horizontal subdivisions - for ( j = 0 ; ; j = (j + 2) % (width - 1) ) { - // check subdivided midpoints against control points - - // FIXME: also check midpoints of adjacent patches against the control points - // this would basically stitch all patches in the same LOD group together. - - maxLen = 0; - for ( i = 0 ; i < height ; i++ ) { - vec3_t midxyz; - vec3_t midxyz2; - vec3_t dir; - vec3_t projected; - float d; - - // calculate the point on the curve - for ( l = 0 ; l < 3 ; l++ ) { - midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2 - + ctrl[i][j+2].xyz[l] ) * 0.25f; - } - - // see how far off the line it is - // using dist-from-line will not account for internal - // texture warping, but it gives a lot less polygons than - // dist-from-midpoint - VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz ); - VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir ); - VectorNormalize( dir ); - - d = DotProduct( midxyz, dir ); - VectorScale( dir, d, projected ); - VectorSubtract( midxyz, projected, midxyz2); - len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later - if ( len > maxLen ) { - maxLen = len; - } - } - - maxLen = sqrt(maxLen); - - // if all the points are on the lines, remove the entire columns - if ( maxLen < 0.1f ) { - errorTable[dir][j+1] = 999; - // if we go over the whole grid twice without adding any columns, stop - if (++consecutiveComplete >= width) - break; - continue; - } - - // see if we want to insert subdivided columns - if ( width + 2 > MAX_GRID_SIZE ) { - errorTable[dir][j+1] = 1.0f/maxLen; - break; // can't subdivide any more - } - - if ( maxLen <= r_subdivisions->value ) { - errorTable[dir][j+1] = 1.0f/maxLen; - // if we go over the whole grid twice without adding any columns, stop - if (++consecutiveComplete >= width) - break; - continue; // didn't need subdivision - } - - errorTable[dir][j+2] = 1.0f/maxLen; - - consecutiveComplete = 0; - - // insert two columns and replace the peak - width += 2; - for ( i = 0 ; i < height ; i++ ) { - LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev ); - LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next ); - LerpDrawVert( &prev, &next, &mid ); - - for ( k = width - 1 ; k > j + 3 ; k-- ) { - ctrl[i][k] = ctrl[i][k-2]; - } - ctrl[i][j + 1] = prev; - ctrl[i][j + 2] = mid; - ctrl[i][j + 3] = next; - } - - // skip the new one, we'll get it on the next pass - j += 2; - } - - Transpose( width, height, ctrl ); - t = width; - width = height; - height = t; - } - - - // put all the aproximating points on the curve - PutPointsOnCurve( ctrl, width, height ); - - // cull out any rows or columns that are colinear - for ( i = 1 ; i < width-1 ; i++ ) { - if ( errorTable[0][i] != 999 ) { - continue; - } - for ( j = i+1 ; j < width ; j++ ) { - for ( k = 0 ; k < height ; k++ ) { - ctrl[k][j-1] = ctrl[k][j]; - } - errorTable[0][j-1] = errorTable[0][j]; - } - width--; - } - - for ( i = 1 ; i < height-1 ; i++ ) { - if ( errorTable[1][i] != 999 ) { - continue; - } - for ( j = i+1 ; j < height ; j++ ) { - for ( k = 0 ; k < width ; k++ ) { - ctrl[j-1][k] = ctrl[j][k]; - } - errorTable[1][j-1] = errorTable[1][j]; - } - height--; - } - -#if 1 - // flip for longest tristrips as an optimization - // the results should be visually identical with or - // without this step - if ( height > width ) { - Transpose( width, height, ctrl ); - InvertErrorTable( errorTable, width, height ); - t = width; - width = height; - height = t; - InvertCtrl( width, height, ctrl ); - } -#endif - - // calculate indexes - numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); - - // calculate normals - MakeMeshNormals( width, height, ctrl ); -#ifdef USE_VERT_TANGENT_SPACE - MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes); -#endif - - return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); -} - -/* -=============== -R_GridInsertColumn -=============== -*/ -srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ) { - int i, j; - int width, height, oldwidth; - srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - float lodRadius; - vec3_t lodOrigin; - int numIndexes; - static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]; - - oldwidth = 0; - width = grid->width + 1; - if (width > MAX_GRID_SIZE) - return NULL; - height = grid->height; - for (i = 0; i < width; i++) { - if (i == column) { - //insert new column - for (j = 0; j < grid->height; j++) { - LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] ); - if (j == row) - VectorCopy(point, ctrl[j][i].xyz); - } - errorTable[0][i] = loderror; - continue; - } - errorTable[0][i] = grid->widthLodError[oldwidth]; - for (j = 0; j < grid->height; j++) { - ctrl[j][i] = grid->verts[j * grid->width + oldwidth]; - } - oldwidth++; - } - for (j = 0; j < grid->height; j++) { - errorTable[1][j] = grid->heightLodError[j]; - } - // put all the aproximating points on the curve - //PutPointsOnCurve( ctrl, width, height ); - - // calculate indexes - numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); - - // calculate normals - MakeMeshNormals( width, height, ctrl ); - - VectorCopy(grid->lodOrigin, lodOrigin); - lodRadius = grid->lodRadius; - // free the old grid - R_FreeSurfaceGridMesh(grid); - // create a new grid - grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); - grid->lodRadius = lodRadius; - VectorCopy(lodOrigin, grid->lodOrigin); - return grid; -} - -/* -=============== -R_GridInsertRow -=============== -*/ -srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ) { - int i, j; - int width, height, oldheight; - srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - float lodRadius; - vec3_t lodOrigin; - int numIndexes; - static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]; - - oldheight = 0; - width = grid->width; - height = grid->height + 1; - if (height > MAX_GRID_SIZE) - return NULL; - for (i = 0; i < height; i++) { - if (i == row) { - //insert new row - for (j = 0; j < grid->width; j++) { - LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] ); - if (j == column) - VectorCopy(point, ctrl[i][j].xyz); - } - errorTable[1][i] = loderror; - continue; - } - errorTable[1][i] = grid->heightLodError[oldheight]; - for (j = 0; j < grid->width; j++) { - ctrl[i][j] = grid->verts[oldheight * grid->width + j]; - } - oldheight++; - } - for (j = 0; j < grid->width; j++) { - errorTable[0][j] = grid->widthLodError[j]; - } - // put all the aproximating points on the curve - //PutPointsOnCurve( ctrl, width, height ); - - // calculate indexes - numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); - - // calculate normals - MakeMeshNormals( width, height, ctrl ); - - VectorCopy(grid->lodOrigin, lodOrigin); - lodRadius = grid->lodRadius; - // free the old grid - R_FreeSurfaceGridMesh(grid); - // create a new grid - grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); - grid->lodRadius = lodRadius; - VectorCopy(lodOrigin, grid->lodOrigin); - return grid; -} diff --git a/code/renderergl2/tr_extensions.c b/code/renderergl2/tr_extensions.c deleted file mode 100644 index d7e5f1bae0..0000000000 --- a/code/renderergl2/tr_extensions.c +++ /dev/null @@ -1,728 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2011 James Canete (use.less01@gmail.com) - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_extensions.c - extensions needed by the renderer not in sdl_glimp.c - -#ifdef USE_LOCAL_HEADERS -# include "SDL.h" -#else -# include -#endif - -#include "tr_local.h" - -// GL_EXT_draw_range_elements -void (APIENTRY * qglDrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); - -// GL_EXT_multi_draw_arrays -void (APIENTRY * qglMultiDrawArraysEXT) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); -void (APIENTRY * qglMultiDrawElementsEXT) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount); - -// GL_ARB_vertex_shader -void (APIENTRY * qglBindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB * name); -void (APIENTRY * qglGetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length, - GLint * size, GLenum * type, GLcharARB * name); -GLint(APIENTRY * qglGetAttribLocationARB) (GLhandleARB programObj, const GLcharARB * name); - -// GL_ARB_vertex_program -void (APIENTRY * qglVertexAttrib4fARB) (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); -void (APIENTRY * qglVertexAttrib4fvARB) (GLuint, const GLfloat *); -void (APIENTRY * qglVertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized, - GLsizei stride, const GLvoid * pointer); -void (APIENTRY * qglEnableVertexAttribArrayARB) (GLuint index); -void (APIENTRY * qglDisableVertexAttribArrayARB) (GLuint index); - -// GL_ARB_vertex_buffer_object -void (APIENTRY * qglBindBufferARB) (GLenum target, GLuint buffer); -void (APIENTRY * qglDeleteBuffersARB) (GLsizei n, const GLuint * buffers); -void (APIENTRY * qglGenBuffersARB) (GLsizei n, GLuint * buffers); - -GLboolean(APIENTRY * qglIsBufferARB) (GLuint buffer); -void (APIENTRY * qglBufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage); -void (APIENTRY * qglBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data); -void (APIENTRY * qglGetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid * data); - -void (APIENTRY * qglGetBufferParameterivARB) (GLenum target, GLenum pname, GLint * params); -void (APIENTRY * qglGetBufferPointervARB) (GLenum target, GLenum pname, GLvoid * *params); - -// GL_ARB_shader_objects -void (APIENTRY * qglDeleteObjectARB) (GLhandleARB obj); - -GLhandleARB(APIENTRY * qglGetHandleARB) (GLenum pname); -void (APIENTRY * qglDetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj); - -GLhandleARB(APIENTRY * qglCreateShaderObjectARB) (GLenum shaderType); -void (APIENTRY * qglShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB * *string, - const GLint * length); -void (APIENTRY * qglCompileShaderARB) (GLhandleARB shaderObj); - -GLhandleARB(APIENTRY * qglCreateProgramObjectARB) (void); -void (APIENTRY * qglAttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj); -void (APIENTRY * qglLinkProgramARB) (GLhandleARB programObj); -void (APIENTRY * qglUseProgramObjectARB) (GLhandleARB programObj); -void (APIENTRY * qglValidateProgramARB) (GLhandleARB programObj); -void (APIENTRY * qglUniform1fARB) (GLint location, GLfloat v0); -void (APIENTRY * qglUniform2fARB) (GLint location, GLfloat v0, GLfloat v1); -void (APIENTRY * qglUniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -void (APIENTRY * qglUniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -void (APIENTRY * qglUniform1iARB) (GLint location, GLint v0); -void (APIENTRY * qglUniform2iARB) (GLint location, GLint v0, GLint v1); -void (APIENTRY * qglUniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2); -void (APIENTRY * qglUniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -void (APIENTRY * qglUniform1fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform2fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform3fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform4fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform2ivARB) (GLint location, GLsizei count, const GLint * value); -void (APIENTRY * qglUniform3ivARB) (GLint location, GLsizei count, const GLint * value); -void (APIENTRY * qglUniform4ivARB) (GLint location, GLsizei count, const GLint * value); -void (APIENTRY * qglUniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -void (APIENTRY * qglUniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -void (APIENTRY * qglUniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -void (APIENTRY * qglGetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat * params); -void (APIENTRY * qglGetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint * params); -void (APIENTRY * qglGetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog); -void (APIENTRY * qglGetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, - GLhandleARB * obj); -GLint(APIENTRY * qglGetUniformLocationARB) (GLhandleARB programObj, const GLcharARB * name); -void (APIENTRY * qglGetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxIndex, GLsizei * length, - GLint * size, GLenum * type, GLcharARB * name); -void (APIENTRY * qglGetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat * params); -void (APIENTRY * qglGetUniformivARB) (GLhandleARB programObj, GLint location, GLint * params); -void (APIENTRY * qglGetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * source); - -// GL_ARB_texture_compression -void (APIENTRY * qglCompressedTexImage3DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, - GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, - GLint border, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexImage1DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, - GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexSubImage3DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexSubImage2DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, - GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, - GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglGetCompressedTexImageARB)(GLenum target, GLint lod, - GLvoid *img); - -// GL_EXT_framebuffer_object -GLboolean (APIENTRY * qglIsRenderbufferEXT)(GLuint renderbuffer); -void (APIENTRY * qglBindRenderbufferEXT)(GLenum target, GLuint renderbuffer); -void (APIENTRY * qglDeleteRenderbuffersEXT)(GLsizei n, const GLuint *renderbuffers); -void (APIENTRY * qglGenRenderbuffersEXT)(GLsizei n, GLuint *renderbuffers); - -void (APIENTRY * qglRenderbufferStorageEXT)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); - -void (APIENTRY * qglGetRenderbufferParameterivEXT)(GLenum target, GLenum pname, GLint *params); - -GLboolean (APIENTRY * qglIsFramebufferEXT)(GLuint framebuffer); -void (APIENTRY * qglBindFramebufferEXT)(GLenum target, GLuint framebuffer); -void (APIENTRY * qglDeleteFramebuffersEXT)(GLsizei n, const GLuint *framebuffers); -void (APIENTRY * qglGenFramebuffersEXT)(GLsizei n, GLuint *framebuffers); - -GLenum (APIENTRY * qglCheckFramebufferStatusEXT)(GLenum target); - -void (APIENTRY * qglFramebufferTexture1DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level); -void (APIENTRY * qglFramebufferTexture2DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level); -void (APIENTRY * qglFramebufferTexture3DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level, GLint zoffset); - -void (APIENTRY * qglFramebufferRenderbufferEXT)(GLenum target, GLenum attachment, GLenum renderbuffertarget, - GLuint renderbuffer); - -void (APIENTRY * qglGetFramebufferAttachmentParameterivEXT)(GLenum target, GLenum attachment, GLenum pname, GLint *params); - -void (APIENTRY * qglGenerateMipmapEXT)(GLenum target); - -// GL_ARB_occlusion_query -void (APIENTRY * qglGenQueriesARB)(GLsizei n, GLuint *ids); -void (APIENTRY * qglDeleteQueriesARB)(GLsizei n, const GLuint *ids); -GLboolean (APIENTRY * qglIsQueryARB)(GLuint id); -void (APIENTRY * qglBeginQueryARB)(GLenum target, GLuint id); -void (APIENTRY * qglEndQueryARB)(GLenum target); -void (APIENTRY * qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params); -void (APIENTRY * qglGetQueryObjectivARB)(GLuint id, GLenum pname, GLint *params); -void (APIENTRY * qglGetQueryObjectuivARB)(GLuint id, GLenum pname, GLuint *params); - -// GL_EXT_framebuffer_blit -void (APIENTRY * qglBlitFramebufferEXT)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter); - -// GL_EXT_framebuffer_multisample -void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height); - -// GL_ARB_draw_buffers -void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs); - -static qboolean GLimp_HaveExtension(const char *ext) -{ - const char *ptr = Q_stristr( glConfig.extensions_string, ext ); - if (ptr == NULL) - return qfalse; - ptr += strlen(ext); - return ((*ptr == ' ') || (*ptr == '\0')); // verify it's complete string. -} - -void GLimp_InitExtraExtensions() -{ - char *extension; - const char* result[3] = { "...ignoring %s\n", "...using %s\n", "...%s not found\n" }; - - // GL_EXT_draw_range_elements - extension = "GL_EXT_draw_range_elements"; - glRefConfig.drawRangeElements = qfalse; - qglMultiDrawArraysEXT = NULL; - qglMultiDrawElementsEXT = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglDrawRangeElementsEXT = (void *) SDL_GL_GetProcAddress("glDrawRangeElementsEXT"); - - if ( r_ext_draw_range_elements->integer) - glRefConfig.drawRangeElements = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.drawRangeElements], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_multi_draw_arrays - extension = "GL_EXT_multi_draw_arrays"; - glRefConfig.multiDrawArrays = qfalse; - qglMultiDrawArraysEXT = NULL; - qglMultiDrawElementsEXT = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglMultiDrawArraysEXT = (PFNGLMULTIDRAWARRAYSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawArraysEXT"); - qglMultiDrawElementsEXT = (PFNGLMULTIDRAWELEMENTSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawElementsEXT"); - - if ( r_ext_multi_draw_arrays->integer ) - glRefConfig.multiDrawArrays = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.multiDrawArrays], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_vertex_program - //glRefConfig.vertexProgram = qfalse; - extension = "GL_ARB_vertex_program"; - qglVertexAttrib4fARB = NULL; - qglVertexAttrib4fvARB = NULL; - qglVertexAttribPointerARB = NULL; - qglEnableVertexAttribArrayARB = NULL; - qglDisableVertexAttribArrayARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fARB"); - qglVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fvARB"); - qglVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) SDL_GL_GetProcAddress("glVertexAttribPointerARB"); - qglEnableVertexAttribArrayARB = - (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glEnableVertexAttribArrayARB"); - qglDisableVertexAttribArrayARB = - (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glDisableVertexAttribArrayARB"); - - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.vertexProgram = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_vertex_buffer_object - //glRefConfig.vertexBufferObject = qfalse; - extension = "GL_ARB_vertex_buffer_object"; - qglBindBufferARB = NULL; - qglDeleteBuffersARB = NULL; - qglGenBuffersARB = NULL; - qglIsBufferARB = NULL; - qglBufferDataARB = NULL; - qglBufferSubDataARB = NULL; - qglGetBufferSubDataARB = NULL; - qglGetBufferParameterivARB = NULL; - qglGetBufferPointervARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglBindBufferARB = (PFNGLBINDBUFFERARBPROC) SDL_GL_GetProcAddress("glBindBufferARB"); - qglDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) SDL_GL_GetProcAddress("glDeleteBuffersARB"); - qglGenBuffersARB = (PFNGLGENBUFFERSARBPROC) SDL_GL_GetProcAddress("glGenBuffersARB"); - qglIsBufferARB = (PFNGLISBUFFERARBPROC) SDL_GL_GetProcAddress("glIsBufferARB"); - qglBufferDataARB = (PFNGLBUFFERDATAARBPROC) SDL_GL_GetProcAddress("glBufferDataARB"); - qglBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glBufferSubDataARB"); - qglGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glGetBufferSubDataARB"); - qglGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetBufferParameterivARB"); - qglGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC) SDL_GL_GetProcAddress("glGetBufferPointervARB"); - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.vertexBufferObject = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_shader_objects - extension = "GL_ARB_shader_objects"; - //glRefConfig.shaderObjects = qfalse; - qglDeleteObjectARB = NULL; - qglGetHandleARB = NULL; - qglDetachObjectARB = NULL; - qglCreateShaderObjectARB = NULL; - qglShaderSourceARB = NULL; - qglCompileShaderARB = NULL; - qglCreateProgramObjectARB = NULL; - qglAttachObjectARB = NULL; - qglLinkProgramARB = NULL; - qglUseProgramObjectARB = NULL; - qglValidateProgramARB = NULL; - qglUniform1fARB = NULL; - qglUniform2fARB = NULL; - qglUniform3fARB = NULL; - qglUniform4fARB = NULL; - qglUniform1iARB = NULL; - qglUniform2iARB = NULL; - qglUniform3iARB = NULL; - qglUniform4iARB = NULL; - qglUniform1fvARB = NULL; - qglUniform2fvARB = NULL; - qglUniform3fvARB = NULL; - qglUniform4fvARB = NULL; - qglUniform2ivARB = NULL; - qglUniform3ivARB = NULL; - qglUniform4ivARB = NULL; - qglUniformMatrix2fvARB = NULL; - qglUniformMatrix3fvARB = NULL; - qglUniformMatrix4fvARB = NULL; - qglGetObjectParameterfvARB = NULL; - qglGetObjectParameterivARB = NULL; - qglGetInfoLogARB = NULL; - qglGetAttachedObjectsARB = NULL; - qglGetUniformLocationARB = NULL; - qglGetActiveUniformARB = NULL; - qglGetUniformfvARB = NULL; - qglGetUniformivARB = NULL; - qglGetShaderSourceARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB"); - qglGetHandleARB = (PFNGLGETHANDLEARBPROC) SDL_GL_GetProcAddress("glGetHandleARB"); - qglDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) SDL_GL_GetProcAddress("glDetachObjectARB"); - qglCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB"); - qglShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB"); - qglCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB"); - qglCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB"); - qglAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB"); - qglLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB"); - qglUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB"); - qglValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) SDL_GL_GetProcAddress("glValidateProgramARB"); - qglUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB"); - qglUniform2fARB = (PFNGLUNIFORM2FARBPROC) SDL_GL_GetProcAddress("glUniform2fARB"); - qglUniform3fARB = (PFNGLUNIFORM3FARBPROC) SDL_GL_GetProcAddress("glUniform3fARB"); - qglUniform4fARB = (PFNGLUNIFORM4FARBPROC) SDL_GL_GetProcAddress("glUniform4fARB"); - qglUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB"); - qglUniform2iARB = (PFNGLUNIFORM2IARBPROC) SDL_GL_GetProcAddress("glUniform2iARB"); - qglUniform3iARB = (PFNGLUNIFORM3IARBPROC) SDL_GL_GetProcAddress("glUniform3iARB"); - qglUniform4iARB = (PFNGLUNIFORM4IARBPROC) SDL_GL_GetProcAddress("glUniform4iARB"); - qglUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) SDL_GL_GetProcAddress("glUniform1fvARB"); - qglUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) SDL_GL_GetProcAddress("glUniform2fvARB"); - qglUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) SDL_GL_GetProcAddress("glUniform3fvARB"); - qglUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) SDL_GL_GetProcAddress("glUniform4fvARB"); - qglUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) SDL_GL_GetProcAddress("glUniform2ivARB"); - qglUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) SDL_GL_GetProcAddress("glUniform3ivARB"); - qglUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) SDL_GL_GetProcAddress("glUniform4ivARB"); - qglUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix2fvARB"); - qglUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix3fvARB"); - qglUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix4fvARB"); - qglGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterfvARB"); - qglGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB"); - qglGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB"); - qglGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) SDL_GL_GetProcAddress("glGetAttachedObjectsARB"); - qglGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB"); - qglGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) SDL_GL_GetProcAddress("glGetActiveUniformARB"); - qglGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) SDL_GL_GetProcAddress("glGetUniformfvARB"); - qglGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) SDL_GL_GetProcAddress("glGetUniformivARB"); - qglGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glGetShaderSourceARB"); - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.shaderObjects = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_vertex_shader - //glRefConfig.vertexShader = qfalse; - extension = "GL_ARB_vertex_shader"; - qglBindAttribLocationARB = NULL; - qglGetActiveAttribARB = NULL; - qglGetAttribLocationARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - //int reservedComponents; - - //qglGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.maxVertexUniforms); - //qglGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &glConfig.maxVaryingFloats); - //qglGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.maxVertexAttribs); - - //reservedComponents = 16 * 10; // approximation how many uniforms we have besides the bone matrices - -#if 0 - if(glConfig.driverType == GLDRV_MESA) - { - // HACK - // restrict to number of vertex uniforms to 512 because of: - // xreal.x86_64: nv50_program.c:4181: nv50_program_validate_data: Assertion `p->param_nr <= 512' failed - - glConfig.maxVertexUniforms = Q_bound(0, glConfig.maxVertexUniforms, 512); - } -#endif - - //glConfig.maxVertexSkinningBones = (int) Q_bound(0.0, (Q_max(glConfig.maxVertexUniforms - reservedComponents, 0) / 16), MAX_BONES); - //glConfig.vboVertexSkinningAvailable = r_vboVertexSkinning->integer && ((glConfig.maxVertexSkinningBones >= 12) ? qtrue : qfalse); - - qglBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glBindAttribLocationARB"); - qglGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) SDL_GL_GetProcAddress("glGetActiveAttribARB"); - qglGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetAttribLocationARB"); - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.vertexShader = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_shading_language_100 - extension = "GL_ARB_shading_language_100"; - glRefConfig.textureFloat = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - char version[256]; - - Q_strncpyz( version, (char *) qglGetString (GL_SHADING_LANGUAGE_VERSION_ARB), sizeof( version ) ); - - sscanf(version, "%d.%d", &glRefConfig.glslMajorVersion, &glRefConfig.glslMinorVersion); - - ri.Printf(PRINT_ALL, "...using GLSL version %s\n", version); - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - glRefConfig.memInfo = MI_NONE; - - if( GLimp_HaveExtension( "GL_NVX_gpu_memory_info" ) ) - { - glRefConfig.memInfo = MI_NVX; - } - else if( GLimp_HaveExtension( "GL_ATI_meminfo" ) ) - { - glRefConfig.memInfo = MI_ATI; - } - - extension = "GL_ARB_texture_non_power_of_two"; - glRefConfig.textureNonPowerOfTwo = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if(1) //(r_ext_texture_non_power_of_two->integer) - { - glRefConfig.textureNonPowerOfTwo = qtrue; - } - - ri.Printf(PRINT_ALL, result[glRefConfig.textureNonPowerOfTwo], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_texture_float - extension = "GL_ARB_texture_float"; - glRefConfig.textureFloat = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if( r_ext_texture_float->integer ) - { - glRefConfig.textureFloat = qtrue; - } - - ri.Printf(PRINT_ALL, result[glRefConfig.textureFloat], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_half_float_pixel - extension = "GL_ARB_half_float_pixel"; - glRefConfig.halfFloatPixel = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if( r_arb_half_float_pixel->integer ) - glRefConfig.halfFloatPixel = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.halfFloatPixel], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_framebuffer_object - extension = "GL_EXT_framebuffer_object"; - glRefConfig.framebufferObject = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &glRefConfig.maxRenderbufferSize); - glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &glRefConfig.maxColorAttachments); - - qglIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsRenderbufferEXT"); - qglBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindRenderbufferEXT"); - qglDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteRenderbuffersEXT"); - qglGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenRenderbuffersEXT"); - qglRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) SDL_GL_GetProcAddress("glRenderbufferStorageEXT"); - qglGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetRenderbufferParameterivEXT"); - qglIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsFramebufferEXT"); - qglBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindFramebufferEXT"); - qglDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteFramebuffersEXT"); - qglGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenFramebuffersEXT"); - qglCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT"); - qglFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture1DEXT"); - qglFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture2DEXT"); - qglFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture3DEXT"); - qglFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glFramebufferRenderbufferEXT"); - qglGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameterivEXT"); - qglGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) SDL_GL_GetProcAddress("glGenerateMipmapEXT"); - - if(r_ext_framebuffer_object->value) - glRefConfig.framebufferObject = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.framebufferObject], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_packed_depth_stencil - extension = "GL_EXT_packed_depth_stencil"; - glRefConfig.packedDepthStencil = qfalse; - if( GLimp_HaveExtension(extension)) - { - glRefConfig.packedDepthStencil = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.packedDepthStencil], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_occlusion_query - extension = "GL_ARB_occlusion_query"; - glRefConfig.occlusionQuery = qfalse; - if (GLimp_HaveExtension(extension)) - { - qglGenQueriesARB = (PFNGLGENQUERIESARBPROC) SDL_GL_GetProcAddress("glGenQueriesARB"); - qglDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC) SDL_GL_GetProcAddress("glDeleteQueriesARB"); - qglIsQueryARB = (PFNGLISQUERYARBPROC) SDL_GL_GetProcAddress("glIsQueryARB"); - qglBeginQueryARB = (PFNGLBEGINQUERYARBPROC) SDL_GL_GetProcAddress("glBeginQueryARB"); - qglEndQueryARB = (PFNGLENDQUERYARBPROC) SDL_GL_GetProcAddress("glEndQueryARB"); - qglGetQueryivARB = (PFNGLGETQUERYIVARBPROC) SDL_GL_GetProcAddress("glGetQueryivARB"); - qglGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectivARB"); - qglGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectuivARB"); - glRefConfig.occlusionQuery = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.occlusionQuery], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_framebuffer_blit - extension = "GL_EXT_framebuffer_blit"; - glRefConfig.framebufferBlit = qfalse; - if (GLimp_HaveExtension(extension)) - { - qglBlitFramebufferEXT = (void *)SDL_GL_GetProcAddress("glBlitFramebufferEXT"); - glRefConfig.framebufferBlit = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.framebufferBlit], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_framebuffer_multisample - extension = "GL_EXT_framebuffer_multisample"; - glRefConfig.framebufferMultisample = qfalse; - if (GLimp_HaveExtension(extension)) - { - qglRenderbufferStorageMultisampleEXT = (void *)SDL_GL_GetProcAddress("glRenderbufferStorageMultisampleEXT"); - glRefConfig.framebufferMultisample = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.framebufferMultisample], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_texture_sRGB - extension = "GL_EXT_texture_sRGB"; - glRefConfig.textureSrgb = qfalse; - if (GLimp_HaveExtension(extension)) - { - if (r_srgb->integer) - glRefConfig.textureSrgb = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.textureSrgb], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_framebuffer_sRGB - extension = "GL_EXT_framebuffer_sRGB"; - glRefConfig.framebufferSrgb = qfalse; - if (GLimp_HaveExtension(extension)) - { - if (r_srgb->integer) - glRefConfig.framebufferSrgb = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.framebufferSrgb], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_texture_sRGB_decode - extension = "GL_EXT_texture_sRGB_decode"; - glRefConfig.textureSrgbDecode = qfalse; - if (GLimp_HaveExtension(extension)) - { - if (r_srgb->integer) - glRefConfig.textureSrgbDecode = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.textureSrgbDecode], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - - glRefConfig.textureCompression = TCR_NONE; - - // GL_EXT_texture_compression_latc - extension = "GL_EXT_texture_compression_latc"; - if (GLimp_HaveExtension(extension)) - { - if (r_ext_compressed_textures->integer) - glRefConfig.textureCompression |= TCR_LATC; - - ri.Printf(PRINT_ALL, result[r_ext_compressed_textures->integer ? 1 : 0], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_texture_compression_bptc - extension = "GL_ARB_texture_compression_bptc"; - if (GLimp_HaveExtension(extension)) - { - if (r_ext_compressed_textures->integer >= 2) - glRefConfig.textureCompression |= TCR_BPTC; - - ri.Printf(PRINT_ALL, result[(r_ext_compressed_textures->integer >= 2) ? 1 : 0], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_draw_buffers - extension = "GL_ARB_draw_buffers"; - qglDrawBuffersARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglDrawBuffersARB = (void *) SDL_GL_GetProcAddress("glDrawBuffersARB"); - - ri.Printf(PRINT_ALL, result[1], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_depth_clamp - extension = "GL_ARB_depth_clamp"; - glRefConfig.depthClamp = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - glRefConfig.depthClamp = qtrue; - ri.Printf(PRINT_ALL, result[1], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_seamless_cube_map - extension = "GL_ARB_seamless_cube_map"; - glRefConfig.seamlessCubeMap = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if (r_arb_seamless_cube_map->integer) - glRefConfig.seamlessCubeMap = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.seamlessCubeMap], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_vertex_type_2_10_10_10_rev - extension = "GL_ARB_vertex_type_2_10_10_10_rev"; - glRefConfig.packedNormalDataType = GL_UNSIGNED_BYTE; - if( GLimp_HaveExtension( extension ) ) - { - if (r_arb_vertex_type_2_10_10_10_rev->integer) - glRefConfig.packedNormalDataType = GL_UNSIGNED_INT_2_10_10_10_REV; - - ri.Printf(PRINT_ALL, result[r_arb_vertex_type_2_10_10_10_rev->integer ? 1 : 0], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } -} diff --git a/code/renderergl2/tr_extramath.c b/code/renderergl2/tr_extramath.c deleted file mode 100644 index b844678f2e..0000000000 --- a/code/renderergl2/tr_extramath.c +++ /dev/null @@ -1,240 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_extramath.c - extra math needed by the renderer not in qmath.c - -#include "tr_local.h" - -// Some matrix helper functions -// FIXME: do these already exist in ioq3 and I don't know about them? - -void Mat4Zero( mat4_t out ) -{ - out[ 0] = 0.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f; - out[ 1] = 0.0f; out[ 5] = 0.0f; out[ 9] = 0.0f; out[13] = 0.0f; - out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 0.0f; out[14] = 0.0f; - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 0.0f; -} - -void Mat4Identity( mat4_t out ) -{ - out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f; - out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = 0.0f; - out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = 0.0f; - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; -} - -void Mat4Copy( const mat4_t in, mat4_t out ) -{ - out[ 0] = in[ 0]; out[ 4] = in[ 4]; out[ 8] = in[ 8]; out[12] = in[12]; - out[ 1] = in[ 1]; out[ 5] = in[ 5]; out[ 9] = in[ 9]; out[13] = in[13]; - out[ 2] = in[ 2]; out[ 6] = in[ 6]; out[10] = in[10]; out[14] = in[14]; - out[ 3] = in[ 3]; out[ 7] = in[ 7]; out[11] = in[11]; out[15] = in[15]; -} - -void Mat4Multiply( const mat4_t in1, const mat4_t in2, mat4_t out ) -{ - out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3]; - out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3]; - out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3]; - out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3]; - - out[ 4] = in1[ 0] * in2[ 4] + in1[ 4] * in2[ 5] + in1[ 8] * in2[ 6] + in1[12] * in2[ 7]; - out[ 5] = in1[ 1] * in2[ 4] + in1[ 5] * in2[ 5] + in1[ 9] * in2[ 6] + in1[13] * in2[ 7]; - out[ 6] = in1[ 2] * in2[ 4] + in1[ 6] * in2[ 5] + in1[10] * in2[ 6] + in1[14] * in2[ 7]; - out[ 7] = in1[ 3] * in2[ 4] + in1[ 7] * in2[ 5] + in1[11] * in2[ 6] + in1[15] * in2[ 7]; - - out[ 8] = in1[ 0] * in2[ 8] + in1[ 4] * in2[ 9] + in1[ 8] * in2[10] + in1[12] * in2[11]; - out[ 9] = in1[ 1] * in2[ 8] + in1[ 5] * in2[ 9] + in1[ 9] * in2[10] + in1[13] * in2[11]; - out[10] = in1[ 2] * in2[ 8] + in1[ 6] * in2[ 9] + in1[10] * in2[10] + in1[14] * in2[11]; - out[11] = in1[ 3] * in2[ 8] + in1[ 7] * in2[ 9] + in1[11] * in2[10] + in1[15] * in2[11]; - - out[12] = in1[ 0] * in2[12] + in1[ 4] * in2[13] + in1[ 8] * in2[14] + in1[12] * in2[15]; - out[13] = in1[ 1] * in2[12] + in1[ 5] * in2[13] + in1[ 9] * in2[14] + in1[13] * in2[15]; - out[14] = in1[ 2] * in2[12] + in1[ 6] * in2[13] + in1[10] * in2[14] + in1[14] * in2[15]; - out[15] = in1[ 3] * in2[12] + in1[ 7] * in2[13] + in1[11] * in2[14] + in1[15] * in2[15]; -} - -void Mat4Transform( const mat4_t in1, const vec4_t in2, vec4_t out ) -{ - out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3]; - out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3]; - out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3]; - out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3]; -} - -qboolean Mat4Compare( const mat4_t a, const mat4_t b ) -{ - return !(a[ 0] != b[ 0] || a[ 4] != b[ 4] || a[ 8] != b[ 8] || a[12] != b[12] || - a[ 1] != b[ 1] || a[ 5] != b[ 5] || a[ 9] != b[ 9] || a[13] != b[13] || - a[ 2] != b[ 2] || a[ 6] != b[ 6] || a[10] != b[10] || a[14] != b[14] || - a[ 3] != b[ 3] || a[ 7] != b[ 7] || a[11] != b[11] || a[15] != b[15]); -} - -void Mat4Dump( const mat4_t in ) -{ - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 0], in[ 4], in[ 8], in[12]); - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 1], in[ 5], in[ 9], in[13]); - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 2], in[ 6], in[10], in[14]); - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 3], in[ 7], in[11], in[15]); -} - -void Mat4Translation( vec3_t vec, mat4_t out ) -{ - out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = vec[0]; - out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = vec[1]; - out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = vec[2]; - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; -} - -void Mat4Ortho( float left, float right, float bottom, float top, float znear, float zfar, mat4_t out ) -{ - out[ 0] = 2.0f / (right - left); out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = -(right + left) / (right - left); - out[ 1] = 0.0f; out[ 5] = 2.0f / (top - bottom); out[ 9] = 0.0f; out[13] = -(top + bottom) / (top - bottom); - out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 2.0f / (zfar - znear); out[14] = -(zfar + znear) / (zfar - znear); - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; -} - -void Mat4View(vec3_t axes[3], vec3_t origin, mat4_t out) -{ - out[0] = axes[0][0]; - out[1] = axes[1][0]; - out[2] = axes[2][0]; - out[3] = 0; - - out[4] = axes[0][1]; - out[5] = axes[1][1]; - out[6] = axes[2][1]; - out[7] = 0; - - out[8] = axes[0][2]; - out[9] = axes[1][2]; - out[10] = axes[2][2]; - out[11] = 0; - - out[12] = -DotProduct(origin, axes[0]); - out[13] = -DotProduct(origin, axes[1]); - out[14] = -DotProduct(origin, axes[2]); - out[15] = 1; -} - -void Mat4SimpleInverse( const mat4_t in, mat4_t out) -{ - vec3_t v; - float invSqrLen; - - VectorCopy(in + 0, v); - invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - out[ 0] = v[0]; out[ 4] = v[1]; out[ 8] = v[2]; out[12] = -DotProduct(v, &in[12]); - - VectorCopy(in + 4, v); - invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - out[ 1] = v[0]; out[ 5] = v[1]; out[ 9] = v[2]; out[13] = -DotProduct(v, &in[12]); - - VectorCopy(in + 8, v); - invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - out[ 2] = v[0]; out[ 6] = v[1]; out[10] = v[2]; out[14] = -DotProduct(v, &in[12]); - - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; -} - -void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c) -{ - c[0] = a[0] * (1.0f - lerp) + b[0] * lerp; - c[1] = a[1] * (1.0f - lerp) + b[1] * lerp; - c[2] = a[2] * (1.0f - lerp) + b[2] * lerp; -} - -qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2) -{ - float radiusSum = radius1 + radius2; - vec3_t diff; - - VectorSubtract(origin1, origin2, diff); - - if (DotProduct(diff, diff) <= radiusSum * radiusSum) - { - return qtrue; - } - - return qfalse; -} - -void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3) -{ - vec3_t diff; - - VectorScale(origin1, 0.5f, origin3); - VectorMA(origin3, 0.5f, origin2, origin3); - - VectorSubtract(origin1, origin2, diff); - *radius3 = VectorLength(diff) * 0.5f + MAX(radius1, radius2); -} - -int NextPowerOfTwo(int in) -{ - int out; - - for (out = 1; out < in; out <<= 1) - ; - - return out; -} - -unsigned short FloatToHalf(float in) -{ - unsigned short out; - - union - { - float f; - unsigned int i; - } f32; - - int sign, inExponent, inFraction; - int outExponent, outFraction; - - f32.f = in; - - sign = (f32.i & 0x80000000) >> 31; - inExponent = (f32.i & 0x7F800000) >> 23; - inFraction = f32.i & 0x007FFFFF; - - outExponent = CLAMP(inExponent - 127, -15, 16) + 15; - - outFraction = 0; - if (outExponent == 0x1F) - { - if (inExponent == 0xFF && inFraction != 0) - outFraction = 0x3FF; - } - else if (outExponent == 0x00) - { - if (inExponent == 0x00 && inFraction != 0) - outFraction = 0x3FF; - } - else - outFraction = inFraction >> 13; - - out = (sign << 15) | (outExponent << 10) | outFraction; - - return out; -} diff --git a/code/renderergl2/tr_extramath.h b/code/renderergl2/tr_extramath.h deleted file mode 100644 index 0223c640bd..0000000000 --- a/code/renderergl2/tr_extramath.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_extramath.h - -#ifndef __TR_EXTRAMATH_H__ -#define __TR_EXTRAMATH_H__ - -typedef vec_t mat4_t[16]; -typedef int ivec2_t[2]; -typedef int ivec3_t[3]; -typedef int ivec4_t[4]; - -void Mat4Zero( mat4_t out ); -void Mat4Identity( mat4_t out ); -void Mat4Copy( const mat4_t in, mat4_t out ); -void Mat4Multiply( const mat4_t in1, const mat4_t in2, mat4_t out ); -void Mat4Transform( const mat4_t in1, const vec4_t in2, vec4_t out ); -qboolean Mat4Compare(const mat4_t a, const mat4_t b); -void Mat4Dump( const mat4_t in ); -void Mat4Translation( vec3_t vec, mat4_t out ); -void Mat4Ortho( float left, float right, float bottom, float top, float znear, float zfar, mat4_t out ); -void Mat4View(vec3_t axes[3], vec3_t origin, mat4_t out); -void Mat4SimpleInverse( const mat4_t in, mat4_t out); - -#define VectorCopy2(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) -#define VectorSet2(v,x,y) ((v)[0]=(x),(v)[1]=(y)); - -#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) -#define VectorSet4(v,x,y,z,w) ((v)[0]=(x),(v)[1]=(y),(v)[2]=(z),(v)[3]=(w)) -#define DotProduct4(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2] + (a)[3]*(b)[3]) -#define VectorScale4(a,b,c) ((c)[0]=(a)[0]*(b),(c)[1]=(a)[1]*(b),(c)[2]=(a)[2]*(b),(c)[3]=(a)[3]*(b)) - -#define VectorCopy5(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3],(b)[4]=(a)[4]) - -#define OffsetByteToFloat(a) ((float)(a) * 1.0f/127.5f - 1.0f) -#define FloatToOffsetByte(a) (byte)((a) * 127.5f + 128.0f) -#define ByteToFloat(a) ((float)(a) * 1.0f/255.0f) -#define FloatToByte(a) (byte)((a) * 255.0f) - -#define RGBtosRGB(a) (((a) < 0.0031308f) ? (12.92f * (a)) : (1.055f * pow((a), 0.41666f) - 0.055f)) -#define sRGBtoRGB(a) (((a) <= 0.04045f) ? ((a) / 12.92f) : (pow((((a) + 0.055f) / 1.055f), 2.4)) ) - -static ID_INLINE int VectorCompare4(const vec4_t v1, const vec4_t v2) -{ - if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3]) - { - return 0; - } - return 1; -} - -static ID_INLINE int VectorCompare5(const vec5_t v1, const vec5_t v2) -{ - if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3] || v1[4] != v2[4]) - { - return 0; - } - return 1; -} - -void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c); - - -qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2); -void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3); - -#ifndef SGN -#define SGN(x) (((x) >= 0) ? !!(x) : -1) -#endif - -#ifndef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef CLAMP -#define CLAMP(a,b,c) MIN(MAX((a),(b)),(c)) -#endif - -int NextPowerOfTwo(int in); -unsigned short FloatToHalf(float in); - -#endif diff --git a/code/renderergl2/tr_extratypes.h b/code/renderergl2/tr_extratypes.h deleted file mode 100644 index 84e39a76ef..0000000000 --- a/code/renderergl2/tr_extratypes.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2009-2011 Andrei Drexler, Richard Allen, James Canete - -This file is part of Reaction source code. - -Reaction source code 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. - -Reaction source code 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 Reaction source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#ifndef __TR_EXTRATYPES_H__ -#define __TR_EXTRATYPES_H__ - -// tr_extratypes.h, for mods that want to extend tr_types.h without losing compatibility with original VMs - -// extra refdef flags start at 0x0008 -#define RDF_NOFOG 0x0008 // don't apply fog to polys added using RE_AddPolyToScene -#define RDF_EXTRA 0x0010 // Makro - refdefex_t to follow after refdef_t -#define RDF_SUNLIGHT 0x0020 // SmileTheory - render sunlight and shadows - -typedef struct { - float blurFactor; - float sunDir[3]; - float sunCol[3]; - float sunAmbCol[3]; -} refdefex_t; - -#endif diff --git a/code/renderergl2/tr_fbo.c b/code/renderergl2/tr_fbo.c deleted file mode 100644 index c642b73237..0000000000 --- a/code/renderergl2/tr_fbo.c +++ /dev/null @@ -1,867 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2006 Kirk Barnes -Copyright (C) 2006-2008 Robert Beckebans - -This file is part of XreaL source code. - -XreaL source code 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. - -XreaL source code 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 XreaL source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_fbo.c -#include "tr_local.h" - -/* -============= -R_CheckFBO -============= -*/ -qboolean R_CheckFBO(const FBO_t * fbo) -{ - int code; - int id; - - qglGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &id); - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer); - - code = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - if(code == GL_FRAMEBUFFER_COMPLETE_EXT) - { - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id); - return qtrue; - } - - // an error occured - switch (code) - { - case GL_FRAMEBUFFER_COMPLETE_EXT: - break; - - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Unsupported framebuffer format\n", fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete attachment\n", fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing attachment\n", fbo->name); - break; - - //case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: - // ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, duplicate attachment\n", fbo->name); - // break; - - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same dimensions\n", - fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same format\n", - fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing draw buffer\n", fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing read buffer\n", fbo->name); - break; - - default: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) unknown error 0x%X\n", fbo->name, code); - //ri.Error(ERR_FATAL, "R_CheckFBO: (%s) unknown error 0x%X", fbo->name, code); - //assert(0); - break; - } - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id); - - return qfalse; -} - -/* -============ -FBO_Create -============ -*/ -FBO_t *FBO_Create(const char *name, int width, int height) -{ - FBO_t *fbo; - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "FBO_Create: \"%s\" is too long", name); - } - - if(width <= 0 || width > glRefConfig.maxRenderbufferSize) - { - ri.Error(ERR_DROP, "FBO_Create: bad width %i", width); - } - - if(height <= 0 || height > glRefConfig.maxRenderbufferSize) - { - ri.Error(ERR_DROP, "FBO_Create: bad height %i", height); - } - - if(tr.numFBOs == MAX_FBOS) - { - ri.Error(ERR_DROP, "FBO_Create: MAX_FBOS hit"); - } - - fbo = tr.fbos[tr.numFBOs] = ri.Hunk_Alloc(sizeof(*fbo), h_low); - Q_strncpyz(fbo->name, name, sizeof(fbo->name)); - fbo->index = tr.numFBOs++; - fbo->width = width; - fbo->height = height; - - qglGenFramebuffersEXT(1, &fbo->frameBuffer); - - return fbo; -} - -void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample) -{ - uint32_t *pRenderBuffer; - GLenum attachment; - qboolean absent; - - switch(format) - { - case GL_RGB: - case GL_RGBA: - case GL_RGB8: - case GL_RGBA8: - case GL_RGB16F_ARB: - case GL_RGBA16F_ARB: - case GL_RGB32F_ARB: - case GL_RGBA32F_ARB: - fbo->colorFormat = format; - pRenderBuffer = &fbo->colorBuffers[index]; - attachment = GL_COLOR_ATTACHMENT0_EXT + index; - break; - - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16_ARB: - case GL_DEPTH_COMPONENT24_ARB: - case GL_DEPTH_COMPONENT32_ARB: - fbo->depthFormat = format; - pRenderBuffer = &fbo->depthBuffer; - attachment = GL_DEPTH_ATTACHMENT_EXT; - break; - - case GL_STENCIL_INDEX: - case GL_STENCIL_INDEX1_EXT: - case GL_STENCIL_INDEX4_EXT: - case GL_STENCIL_INDEX8_EXT: - case GL_STENCIL_INDEX16_EXT: - fbo->stencilFormat = format; - pRenderBuffer = &fbo->stencilBuffer; - attachment = GL_STENCIL_ATTACHMENT_EXT; - break; - - case GL_DEPTH_STENCIL_EXT: - case GL_DEPTH24_STENCIL8_EXT: - fbo->packedDepthStencilFormat = format; - pRenderBuffer = &fbo->packedDepthStencilBuffer; - attachment = 0; // special for stencil and depth - break; - - default: - ri.Printf(PRINT_WARNING, "FBO_CreateBuffer: invalid format %d\n", format); - return; - } - - absent = *pRenderBuffer == 0; - if (absent) - qglGenRenderbuffersEXT(1, pRenderBuffer); - - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, *pRenderBuffer); - if (multisample && glRefConfig.framebufferMultisample) - { - qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, multisample, format, fbo->width, fbo->height); - } - else - { - qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, fbo->width, fbo->height); - } - - if(absent) - { - if (attachment == 0) - { - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer); - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer); - } - else - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer); - } -} - - -/* -================= -R_AttachFBOTexture1D -================= -*/ -void R_AttachFBOTexture1D(int texId, int index) -{ - if(index < 0 || index >= glRefConfig.maxColorAttachments) - { - ri.Printf(PRINT_WARNING, "R_AttachFBOTexture1D: invalid attachment index %i\n", index); - return; - } - - qglFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_1D, texId, 0); -} - -/* -================= -R_AttachFBOTexture2D -================= -*/ -void R_AttachFBOTexture2D(int target, int texId, int index) -{ - if(target != GL_TEXTURE_2D && (target < GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB || target > GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) - { - ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid target %i\n", target); - return; - } - - if(index < 0 || index >= glRefConfig.maxColorAttachments) - { - ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid attachment index %i\n", index); - return; - } - - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, texId, 0); -} - -/* -================= -R_AttachFBOTexture3D -================= -*/ -void R_AttachFBOTexture3D(int texId, int index, int zOffset) -{ - if(index < 0 || index >= glRefConfig.maxColorAttachments) - { - ri.Printf(PRINT_WARNING, "R_AttachFBOTexture3D: invalid attachment index %i\n", index); - return; - } - - qglFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_3D_EXT, texId, 0, zOffset); -} - -/* -================= -R_AttachFBOTextureDepth -================= -*/ -void R_AttachFBOTextureDepth(int texId) -{ - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0); -} - -/* -================= -R_AttachFBOTexturePackedDepthStencil -================= -*/ -void R_AttachFBOTexturePackedDepthStencil(int texId) -{ - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0); - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0); -} - -void FBO_AttachTextureImage(image_t *img, int index) -{ - if (!glState.currentFBO) - { - ri.Printf(PRINT_WARNING, "FBO: attempted to attach a texture image with no FBO bound!\n"); - return; - } - - R_AttachFBOTexture2D(GL_TEXTURE_2D, img->texnum, index); - glState.currentFBO->colorImage[index] = img; -} - -/* -============ -FBO_Bind -============ -*/ -void FBO_Bind(FBO_t * fbo) -{ - if (glState.currentFBO == fbo) - return; - - if (r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - if (fbo) - GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo->name)); - else - GLimp_LogComment("--- FBO_Bind ( NULL ) ---\n"); - } - - if (!fbo) - { - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - //qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); - glState.currentFBO = NULL; - - return; - } - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer); - - /* - if(fbo->colorBuffers[0]) - { - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->colorBuffers[0]); - } - */ - - /* - if(fbo->depthBuffer) - { - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->depthBuffer); - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthBuffer); - } - */ - - glState.currentFBO = fbo; -} - -/* -============ -FBO_Init -============ -*/ -void FBO_Init(void) -{ - int i; - // int width, height, hdrFormat, multisample; - int hdrFormat, multisample; - - ri.Printf(PRINT_ALL, "------- FBO_Init -------\n"); - - if(!glRefConfig.framebufferObject) - return; - - tr.numFBOs = 0; - - GL_CheckErrors(); - - R_IssuePendingRenderCommands(); - -/* if(glRefConfig.textureNonPowerOfTwo) - { - width = glConfig.vidWidth; - height = glConfig.vidHeight; - } - else - { - width = NextPowerOfTwo(glConfig.vidWidth); - height = NextPowerOfTwo(glConfig.vidHeight); - } */ - - hdrFormat = GL_RGBA8; - if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat) - { - hdrFormat = GL_RGBA16F_ARB; - } - - qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample); - - if (r_ext_framebuffer_multisample->integer < multisample) - { - multisample = r_ext_framebuffer_multisample->integer; - } - - if (multisample < 2 || !glRefConfig.framebufferBlit) - multisample = 0; - - if (multisample != r_ext_framebuffer_multisample->integer) - { - ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample); - } - - // only create a render FBO if we need to resolve MSAA or do HDR - // otherwise just render straight to the screen (tr.renderFbo = NULL) - if (multisample && glRefConfig.framebufferMultisample) - { - tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_Bind(tr.renderFbo); - - FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample); - FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample); - - R_CheckFBO(tr.renderFbo); - - - tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_Bind(tr.msaaResolveFbo); - - //FBO_CreateBuffer(tr.msaaResolveFbo, hdrFormat, 0, 0); - FBO_AttachTextureImage(tr.renderImage, 0); - - //FBO_CreateBuffer(tr.msaaResolveFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); - R_AttachFBOTextureDepth(tr.renderDepthImage->texnum); - - R_CheckFBO(tr.msaaResolveFbo); - } - else if (r_hdr->integer) - { - tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_Bind(tr.renderFbo); - - //FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, 0); - FBO_AttachTextureImage(tr.renderImage, 0); - - //FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); - R_AttachFBOTextureDepth(tr.renderDepthImage->texnum); - - R_CheckFBO(tr.renderFbo); - } - - // clear render buffer - // this fixes the corrupt screen bug with r_hdr 1 on older hardware - if (tr.renderFbo) - { - FBO_Bind(tr.renderFbo); - qglClearColor( 1, 0, 0.5, 1 ); - qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - FBO_Bind(NULL); - } - - if (r_drawSunRays->integer) - { - tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_Bind(tr.sunRaysFbo); - - FBO_AttachTextureImage(tr.sunRaysImage, 0); - - R_AttachFBOTextureDepth(tr.renderDepthImage->texnum); - - R_CheckFBO(tr.sunRaysFbo); - } - - // FIXME: Don't use separate color/depth buffers for a shadow buffer - if (MAX_DRAWN_PSHADOWS && tr.pshadowMaps[0]) - { - for( i = 0; i < MAX_DRAWN_PSHADOWS; i++) - { - tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height); - FBO_Bind(tr.pshadowFbos[i]); - - //FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0); - FBO_AttachTextureImage(tr.pshadowMaps[i], 0); - - FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0); - //R_AttachFBOTextureDepth(tr.textureDepthImage->texnum); - - R_CheckFBO(tr.pshadowFbos[i]); - } - } - - if (tr.sunShadowDepthImage[0]) - { - for ( i = 0; i < 3; i++) - { - tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height); - FBO_Bind(tr.sunShadowFbo[i]); - - //FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0); - //FBO_AttachTextureImage(tr.sunShadowImage, 0); - qglDrawBuffer(GL_NONE); - qglReadBuffer(GL_NONE); - - //FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); - R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum); - - R_CheckFBO(tr.sunShadowFbo[i]); - - } - - tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height); - FBO_Bind(tr.screenShadowFbo); - - FBO_AttachTextureImage(tr.screenShadowImage, 0); - - R_CheckFBO(tr.screenShadowFbo); - } - - for (i = 0; i < 2; i++) - { - tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height); - FBO_Bind(tr.textureScratchFbo[i]); - - //FBO_CreateBuffer(tr.textureScratchFbo[i], GL_RGBA8, 0, 0); - FBO_AttachTextureImage(tr.textureScratchImage[i], 0); - - R_CheckFBO(tr.textureScratchFbo[i]); - } - - { - tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height); - FBO_Bind(tr.calcLevelsFbo); - - //FBO_CreateBuffer(tr.calcLevelsFbo, hdrFormat, 0, 0); - FBO_AttachTextureImage(tr.calcLevelsImage, 0); - - R_CheckFBO(tr.calcLevelsFbo); - } - - { - tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height); - FBO_Bind(tr.targetLevelsFbo); - - //FBO_CreateBuffer(tr.targetLevelsFbo, hdrFormat, 0, 0); - FBO_AttachTextureImage(tr.targetLevelsImage, 0); - - R_CheckFBO(tr.targetLevelsFbo); - } - - for (i = 0; i < 2; i++) - { - tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height); - FBO_Bind(tr.quarterFbo[i]); - - //FBO_CreateBuffer(tr.quarterFbo[i], hdrFormat, 0, 0); - FBO_AttachTextureImage(tr.quarterImage[i], 0); - - R_CheckFBO(tr.quarterFbo[i]); - } - - if (r_ssao->integer) - { - tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height); - FBO_Bind(tr.hdrDepthFbo); - - FBO_AttachTextureImage(tr.hdrDepthImage, 0); - - R_CheckFBO(tr.hdrDepthFbo); - - tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height); - FBO_Bind(tr.screenSsaoFbo); - - FBO_AttachTextureImage(tr.screenSsaoImage, 0); - - R_CheckFBO(tr.screenSsaoFbo); - } - - if (tr.renderCubeImage) - { - tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height); - FBO_Bind(tr.renderCubeFbo); - - //FBO_AttachTextureImage(tr.renderCubeImage, 0); - R_AttachFBOTexture2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, tr.renderCubeImage->texnum, 0); - glState.currentFBO->colorImage[0] = tr.renderCubeImage; - - FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); - - R_CheckFBO(tr.renderCubeFbo); - } - - GL_CheckErrors(); - - FBO_Bind(NULL); -} - -/* -============ -FBO_Shutdown -============ -*/ -void FBO_Shutdown(void) -{ - int i, j; - FBO_t *fbo; - - ri.Printf(PRINT_ALL, "------- FBO_Shutdown -------\n"); - - if(!glRefConfig.framebufferObject) - return; - - FBO_Bind(NULL); - - for(i = 0; i < tr.numFBOs; i++) - { - fbo = tr.fbos[i]; - - for(j = 0; j < glRefConfig.maxColorAttachments; j++) - { - if(fbo->colorBuffers[j]) - qglDeleteRenderbuffersEXT(1, &fbo->colorBuffers[j]); - } - - if(fbo->depthBuffer) - qglDeleteRenderbuffersEXT(1, &fbo->depthBuffer); - - if(fbo->stencilBuffer) - qglDeleteRenderbuffersEXT(1, &fbo->stencilBuffer); - - if(fbo->frameBuffer) - qglDeleteFramebuffersEXT(1, &fbo->frameBuffer); - } -} - -/* -============ -R_FBOList_f -============ -*/ -void R_FBOList_f(void) -{ - int i; - FBO_t *fbo; - - if(!glRefConfig.framebufferObject) - { - ri.Printf(PRINT_ALL, "GL_EXT_framebuffer_object is not available.\n"); - return; - } - - ri.Printf(PRINT_ALL, " size name\n"); - ri.Printf(PRINT_ALL, "----------------------------------------------------------\n"); - - for(i = 0; i < tr.numFBOs; i++) - { - fbo = tr.fbos[i]; - - ri.Printf(PRINT_ALL, " %4i: %4i %4i %s\n", i, fbo->width, fbo->height, fbo->name); - } - - ri.Printf(PRINT_ALL, " %i FBOs\n", tr.numFBOs); -} - -// FIXME -extern void RB_SetGL2D (void); - -void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend) -{ - ivec4_t dstBox, srcBox; - vec2_t srcTexScale; - vec4_t color; - vec4_t quadVerts[4]; - vec2_t texCoords[4]; - vec2_t invTexRes; - FBO_t *oldFbo = glState.currentFBO; - mat4_t projection; - int width, height; - - if (!src) - return; - - if (inSrcBox) - { - VectorSet4(srcBox, inSrcBox[0], inSrcBox[1], inSrcBox[0] + inSrcBox[2], inSrcBox[1] + inSrcBox[3]); - } - else - { - VectorSet4(srcBox, 0, 0, src->width, src->height); - } - - // framebuffers are 0 bottom, Y up. - if (inDstBox) - { - if (dst) - { - dstBox[0] = inDstBox[0]; - dstBox[1] = dst->height - inDstBox[1] - inDstBox[3]; - dstBox[2] = inDstBox[0] + inDstBox[2]; - dstBox[3] = dst->height - inDstBox[1]; - } - else - { - dstBox[0] = inDstBox[0]; - dstBox[1] = glConfig.vidHeight - inDstBox[1] - inDstBox[3]; - dstBox[2] = inDstBox[0] + inDstBox[2]; - dstBox[3] = glConfig.vidHeight - inDstBox[1]; - } - } - else if (dst) - { - VectorSet4(dstBox, 0, dst->height, dst->width, 0); - } - else - { - VectorSet4(dstBox, 0, glConfig.vidHeight, glConfig.vidWidth, 0); - } - - if (inSrcTexScale) - { - VectorCopy2(inSrcTexScale, srcTexScale); - } - else - { - srcTexScale[0] = srcTexScale[1] = 1.0f; - } - - if (inColor) - { - VectorCopy4(inColor, color); - } - else - { - VectorCopy4(colorWhite, color); - } - - if (!shaderProgram) - { - shaderProgram = &tr.textureColorShader; - } - - FBO_Bind(dst); - - if (glState.currentFBO) - { - width = glState.currentFBO->width; - height = glState.currentFBO->height; - } - else - { - width = glConfig.vidWidth; - height = glConfig.vidHeight; - } - - qglViewport( 0, 0, width, height ); - qglScissor( 0, 0, width, height ); - - Mat4Ortho(0, width, height, 0, 0, 1, projection); - - qglDisable( GL_CULL_FACE ); - - GL_BindToTMU(src, TB_COLORMAP); - - VectorSet4(quadVerts[0], dstBox[0], dstBox[1], 0, 1); - VectorSet4(quadVerts[1], dstBox[2], dstBox[1], 0, 1); - VectorSet4(quadVerts[2], dstBox[2], dstBox[3], 0, 1); - VectorSet4(quadVerts[3], dstBox[0], dstBox[3], 0, 1); - - texCoords[0][0] = srcBox[0] / (float)src->width; texCoords[0][1] = 1.0f - srcBox[1] / (float)src->height; - texCoords[1][0] = srcBox[2] / (float)src->width; texCoords[1][1] = 1.0f - srcBox[1] / (float)src->height; - texCoords[2][0] = srcBox[2] / (float)src->width; texCoords[2][1] = 1.0f - srcBox[3] / (float)src->height; - texCoords[3][0] = srcBox[0] / (float)src->width; texCoords[3][1] = 1.0f - srcBox[3] / (float)src->height; - - invTexRes[0] = 1.0f / src->width * srcTexScale[0]; - invTexRes[1] = 1.0f / src->height * srcTexScale[1]; - - GL_State( blend ); - - GLSL_BindProgram(shaderProgram); - - GLSL_SetUniformMat4(shaderProgram, UNIFORM_MODELVIEWPROJECTIONMATRIX, projection); - GLSL_SetUniformVec4(shaderProgram, UNIFORM_COLOR, color); - GLSL_SetUniformVec2(shaderProgram, UNIFORM_INVTEXRES, invTexRes); - GLSL_SetUniformVec2(shaderProgram, UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax); - GLSL_SetUniformVec3(shaderProgram, UNIFORM_TONEMINAVGMAXLINEAR, tr.refdef.toneMinAvgMaxLinear); - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - - FBO_Bind(oldFbo); -} - -void FBO_Blit(FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend) -{ - ivec4_t srcBox; - - if (!src) - { - ri.Printf(PRINT_WARNING, "Tried to blit from a NULL FBO!\n"); - return; - } - - // framebuffers are 0 bottom, Y up. - if (inSrcBox) - { - srcBox[0] = inSrcBox[0]; - srcBox[1] = src->height - inSrcBox[1] - inSrcBox[3]; - srcBox[2] = inSrcBox[2]; - srcBox[3] = inSrcBox[3]; - } - else - { - VectorSet4(srcBox, 0, src->height, src->width, -src->height); - } - - FBO_BlitFromTexture(src->colorImage[0], srcBox, srcTexScale, dst, dstBox, shaderProgram, color, blend | GLS_DEPTHTEST_DISABLE); -} - -void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter) -{ - ivec4_t srcBoxFinal, dstBoxFinal; - GLuint srcFb, dstFb; - - if (!glRefConfig.framebufferBlit) - { - FBO_Blit(src, srcBox, NULL, dst, dstBox, NULL, NULL, 0); - return; - } - - // get to a neutral state first - //FBO_Bind(NULL); - - srcFb = src ? src->frameBuffer : 0; - dstFb = dst ? dst->frameBuffer : 0; - - if (!srcBox) - { - if (src) - { - VectorSet4(srcBoxFinal, 0, 0, src->width, src->height); - } - else - { - VectorSet4(srcBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight); - } - } - else - { - VectorSet4(srcBoxFinal, srcBox[0], srcBox[1], srcBox[0] + srcBox[2], srcBox[1] + srcBox[3]); - } - - if (!dstBox) - { - if (dst) - { - VectorSet4(dstBoxFinal, 0, 0, dst->width, dst->height); - } - else - { - VectorSet4(dstBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight); - } - } - else - { - VectorSet4(dstBoxFinal, dstBox[0], dstBox[1], dstBox[0] + dstBox[2], dstBox[1] + dstBox[3]); - } - - qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, srcFb); - qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dstFb); - qglBlitFramebufferEXT(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3], - dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3], - buffers, filter); - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glState.currentFBO = NULL; -} diff --git a/code/renderergl2/tr_fbo.h b/code/renderergl2/tr_fbo.h deleted file mode 100644 index b5ab18c19f..0000000000 --- a/code/renderergl2/tr_fbo.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_fbo.h - -#ifndef __TR_FBO_H__ -#define __TR_FBO_H__ - -struct image_s; -struct shaderProgram_s; - -typedef struct FBO_s -{ - char name[MAX_QPATH]; - - int index; - - uint32_t frameBuffer; - - uint32_t colorBuffers[16]; - int colorFormat; - struct image_s *colorImage[16]; - - uint32_t depthBuffer; - int depthFormat; - - uint32_t stencilBuffer; - int stencilFormat; - - uint32_t packedDepthStencilBuffer; - int packedDepthStencilFormat; - - int width; - int height; -} FBO_t; - -void FBO_Bind(FBO_t *fbo); -void FBO_Init(void); -void FBO_Shutdown(void); - -void FBO_BlitFromTexture(struct image_s *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); -void FBO_Blit(FBO_t *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); -void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter); - - -#endif diff --git a/code/renderergl2/tr_flares.c b/code/renderergl2/tr_flares.c deleted file mode 100644 index e1d46d544b..0000000000 --- a/code/renderergl2/tr_flares.c +++ /dev/null @@ -1,557 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_flares.c - -#include "tr_local.h" - -/* -============================================================================= - -LIGHT FLARES - -A light flare is an effect that takes place inside the eye when bright light -sources are visible. The size of the flare reletive to the screen is nearly -constant, irrespective of distance, but the intensity should be proportional to the -projected area of the light source. - -A surface that has been flagged as having a light flare will calculate the depth -buffer value that its midpoint should have when the surface is added. - -After all opaque surfaces have been rendered, the depth buffer is read back for -each flare in view. If the point has not been obscured by a closer surface, the -flare should be drawn. - -Surfaces that have a repeated texture should never be flagged as flaring, because -there will only be a single flare added at the midpoint of the polygon. - -To prevent abrupt popping, the intensity of the flare is interpolated up and -down as it changes visibility. This involves scene to scene state, unlike almost -all other aspects of the renderer, and is complicated by the fact that a single -frame may have multiple scenes. - -RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially -up to five or more times in a frame with 3D status bar icons). - -============================================================================= -*/ - - -// flare states maintain visibility over multiple frames for fading -// layers: view, mirror, menu -typedef struct flare_s { - struct flare_s *next; // for active chain - - int addedFrame; - - qboolean inPortal; // true if in a portal view of the scene - int frameSceneNum; - void *surface; - int fogNum; - - int fadeTime; - - qboolean visible; // state of last test - float drawIntensity; // may be non 0 even if !visible due to fading - - int windowX, windowY; - float eyeZ; - - vec3_t origin; - vec3_t color; -} flare_t; - -#define MAX_FLARES 128 - -flare_t r_flareStructs[MAX_FLARES]; -flare_t *r_activeFlares, *r_inactiveFlares; - -int flareCoeff; - -/* -================== -R_SetFlareCoeff -================== -*/ -static void R_SetFlareCoeff( void ) { - - if(r_flareCoeff->value == 0.0f) - flareCoeff = atof(FLARE_STDCOEFF); - else - flareCoeff = r_flareCoeff->value; -} - -/* -================== -R_ClearFlares -================== -*/ -void R_ClearFlares( void ) { - int i; - - Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) ); - r_activeFlares = NULL; - r_inactiveFlares = NULL; - - for ( i = 0 ; i < MAX_FLARES ; i++ ) { - r_flareStructs[i].next = r_inactiveFlares; - r_inactiveFlares = &r_flareStructs[i]; - } - - R_SetFlareCoeff(); -} - - -/* -================== -RB_AddFlare - -This is called at surface tesselation time -================== -*/ -void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) { - int i; - flare_t *f; - vec3_t local; - float d = 1; - vec4_t eye, clip, normalized, window; - - backEnd.pc.c_flareAdds++; - - if(normal && (normal[0] || normal[1] || normal[2])) - { - VectorSubtract( backEnd.viewParms.or.origin, point, local ); - VectorNormalizeFast(local); - d = DotProduct(local, normal); - - // If the viewer is behind the flare don't add it. - if(d < 0) - return; - } - - // if the point is off the screen, don't bother adding it - // calculate screen coordinates and depth - R_TransformModelToClip( point, backEnd.or.modelMatrix, - backEnd.viewParms.projectionMatrix, eye, clip ); - - // check to see if the point is completely off screen - for ( i = 0 ; i < 3 ; i++ ) { - if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) { - return; - } - } - - R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window ); - - if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth - || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) { - return; // shouldn't happen, since we check the clip[] above, except for FP rounding - } - - // see if a flare with a matching surface, scene, and view exists - for ( f = r_activeFlares ; f ; f = f->next ) { - if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal ) { - break; - } - } - - // allocate a new one - if (!f ) { - if ( !r_inactiveFlares ) { - // the list is completely full - return; - } - f = r_inactiveFlares; - r_inactiveFlares = r_inactiveFlares->next; - f->next = r_activeFlares; - r_activeFlares = f; - - f->surface = surface; - f->frameSceneNum = backEnd.viewParms.frameSceneNum; - f->inPortal = backEnd.viewParms.isPortal; - f->addedFrame = -1; - } - - if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) { - f->visible = qfalse; - f->fadeTime = backEnd.refdef.time - 2000; - } - - f->addedFrame = backEnd.viewParms.frameCount; - f->fogNum = fogNum; - - VectorCopy(point, f->origin); - VectorCopy( color, f->color ); - - // fade the intensity of the flare down as the - // light surface turns away from the viewer - VectorScale( f->color, d, f->color ); - - // save info needed to test - f->windowX = backEnd.viewParms.viewportX + window[0]; - f->windowY = backEnd.viewParms.viewportY + window[1]; - - f->eyeZ = eye[2]; -} - -/* -================== -RB_AddDlightFlares -================== -*/ -void RB_AddDlightFlares( void ) { - dlight_t *l; - int i, j, k; - fog_t *fog = NULL; - - if ( !r_flares->integer ) { - return; - } - - l = backEnd.refdef.dlights; - - if(tr.world) - fog = tr.world->fogs; - - for (i=0 ; inumfogs ; j++ ) { - fog = &tr.world->fogs[j]; - for ( k = 0 ; k < 3 ; k++ ) { - if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) { - break; - } - } - if ( k == 3 ) { - break; - } - } - if ( j == tr.world->numfogs ) { - j = 0; - } - } - else - j = 0; - - RB_AddFlare( (void *)l, j, l->origin, l->color, NULL ); - } -} - -/* -=============================================================================== - -FLARE BACK END - -=============================================================================== -*/ - -/* -================== -RB_TestFlare -================== -*/ -void RB_TestFlare( flare_t *f ) { - float depth; - qboolean visible; - float fade; - float screenZ; - FBO_t *oldFbo; - - backEnd.pc.c_flareTests++; - - // doing a readpixels is as good as doing a glFinish(), so - // don't bother with another sync - glState.finishCalled = qfalse; - - // if we're doing multisample rendering, read from the correct FBO - oldFbo = glState.currentFBO; - if (tr.msaaResolveFbo) - { - FBO_Bind(tr.msaaResolveFbo); - } - - // read back the z buffer contents - qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth ); - - // if we're doing multisample rendering, switch to the old FBO - if (tr.msaaResolveFbo) - { - FBO_Bind(oldFbo); - } - - screenZ = backEnd.viewParms.projectionMatrix[14] / - ( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] ); - - visible = ( -f->eyeZ - -screenZ ) < 24; - - if ( visible ) { - if ( !f->visible ) { - f->visible = qtrue; - f->fadeTime = backEnd.refdef.time - 1; - } - fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value; - } else { - if ( f->visible ) { - f->visible = qfalse; - f->fadeTime = backEnd.refdef.time - 1; - } - fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value; - } - - if ( fade < 0 ) { - fade = 0; - } - if ( fade > 1 ) { - fade = 1; - } - - f->drawIntensity = fade; -} - - -/* -================== -RB_RenderFlare -================== -*/ -void RB_RenderFlare( flare_t *f ) { - float size; - vec3_t color; - int iColor[3]; - float distance, intensity, factor; - byte fogFactors[3] = {255, 255, 255}; - - backEnd.pc.c_flareRenders++; - - // We don't want too big values anyways when dividing by distance. - if(f->eyeZ > -1.0f) - distance = 1.0f; - else - distance = -f->eyeZ; - - // calculate the flare size.. - size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance ); - -/* - * This is an alternative to intensity scaling. It changes the size of the flare on screen instead - * with growing distance. See in the description at the top why this is not the way to go. - // size will change ~ 1/r. - size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f)); -*/ - -/* - * As flare sizes stay nearly constant with increasing distance we must decrease the intensity - * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be - * got by considering the ratio of - * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare) - * An important requirement is: - * intensity <= 1 for all distances. - * - * The formula used here to compute the intensity is as follows: - * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2 - * As you can see, the intensity will have a max. of 1 when the distance is 0. - * The coefficient flareCoeff will determine the falloff speed with increasing distance. - */ - - factor = distance + size * sqrt(flareCoeff); - - intensity = flareCoeff * size * size / (factor * factor); - - VectorScale(f->color, f->drawIntensity * intensity, color); - - // Calculations for fogging - if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs) - { - tess.numVertexes = 1; - VectorCopy(f->origin, tess.xyz[0]); - tess.fogNum = f->fogNum; - - RB_CalcModulateColorsByFog(fogFactors); - - // We don't need to render the flare if colors are 0 anyways. - if(!(fogFactors[0] || fogFactors[1] || fogFactors[2])) - return; - } - - iColor[0] = color[0] * fogFactors[0]; - iColor[1] = color[1] * fogFactors[1]; - iColor[2] = color[2] * fogFactors[2]; - - RB_BeginSurface( tr.flareShader, f->fogNum, 0 ); - - // FIXME: use quadstamp? - tess.xyz[tess.numVertexes][0] = f->windowX - size; - tess.xyz[tess.numVertexes][1] = f->windowY - size; - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX - size; - tess.xyz[tess.numVertexes][1] = f->windowY + size; - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX + size; - tess.xyz[tess.numVertexes][1] = f->windowY + size; - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX + size; - tess.xyz[tess.numVertexes][1] = f->windowY - size; - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 1; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 3; - - RB_EndSurface(); -} - -/* -================== -RB_RenderFlares - -Because flares are simulating an occular effect, they should be drawn after -everything (all views) in the entire frame has been drawn. - -Because of the way portals use the depth buffer to mark off areas, the -needed information would be lost after each view, so we are forced to draw -flares after each view. - -The resulting artifact is that flares in mirrors or portals don't dim properly -when occluded by something in the main view, and portal flares that should -extend past the portal edge will be overwritten. -================== -*/ -void RB_RenderFlares (void) { - flare_t *f; - flare_t **prev; - qboolean draw; - mat4_t oldmodelview, oldprojection, matrix; - - if ( !r_flares->integer ) { - return; - } - - if(r_flareCoeff->modified) - { - R_SetFlareCoeff(); - r_flareCoeff->modified = qfalse; - } - - // Reset currentEntity to world so that any previously referenced entities - // don't have influence on the rendering of these flares (i.e. RF_ renderer flags). - backEnd.currentEntity = &tr.worldEntity; - backEnd.or = backEnd.viewParms.world; - -// RB_AddDlightFlares(); - - // perform z buffer readback on each flare in this view - draw = qfalse; - prev = &r_activeFlares; - while ( ( f = *prev ) != NULL ) { - // throw out any flares that weren't added last frame - if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) { - *prev = f->next; - f->next = r_inactiveFlares; - r_inactiveFlares = f; - continue; - } - - // don't draw any here that aren't from this scene / portal - f->drawIntensity = 0; - if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal ) { - RB_TestFlare( f ); - if ( f->drawIntensity ) { - draw = qtrue; - } else { - // this flare has completely faded out, so remove it from the chain - *prev = f->next; - f->next = r_inactiveFlares; - r_inactiveFlares = f; - continue; - } - } - - prev = &f->next; - } - - if ( !draw ) { - return; // none visible - } - - if ( backEnd.viewParms.isPortal ) { - qglDisable (GL_CLIP_PLANE0); - } - - Mat4Copy(glState.projection, oldprojection); - Mat4Copy(glState.modelview, oldmodelview); - Mat4Identity(matrix); - GL_SetModelviewMatrix(matrix); - Mat4Ortho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, - backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight, - -99999, 99999, matrix ); - GL_SetProjectionMatrix(matrix); - - for ( f = r_activeFlares ; f ; f = f->next ) { - if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal - && f->drawIntensity ) { - RB_RenderFlare( f ); - } - } - - GL_SetProjectionMatrix(oldprojection); - GL_SetModelviewMatrix(oldmodelview); -} - - - - - diff --git a/code/renderergl2/tr_glsl.c b/code/renderergl2/tr_glsl.c deleted file mode 100644 index 2212c4fe81..0000000000 --- a/code/renderergl2/tr_glsl.c +++ /dev/null @@ -1,1802 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2006-2009 Robert Beckebans - -This file is part of XreaL source code. - -XreaL source code 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. - -XreaL source code 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 XreaL source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_glsl.c -#include "tr_local.h" - -void GLSL_BindNullProgram(void); - -extern const char *fallbackShader_bokeh_vp; -extern const char *fallbackShader_bokeh_fp; -extern const char *fallbackShader_calclevels4x_vp; -extern const char *fallbackShader_calclevels4x_fp; -extern const char *fallbackShader_depthblur_vp; -extern const char *fallbackShader_depthblur_fp; -extern const char *fallbackShader_dlight_vp; -extern const char *fallbackShader_dlight_fp; -extern const char *fallbackShader_down4x_vp; -extern const char *fallbackShader_down4x_fp; -extern const char *fallbackShader_fogpass_vp; -extern const char *fallbackShader_fogpass_fp; -extern const char *fallbackShader_generic_vp; -extern const char *fallbackShader_generic_fp; -extern const char *fallbackShader_lightall_vp; -extern const char *fallbackShader_lightall_fp; -extern const char *fallbackShader_pshadow_vp; -extern const char *fallbackShader_pshadow_fp; -extern const char *fallbackShader_shadowfill_vp; -extern const char *fallbackShader_shadowfill_fp; -extern const char *fallbackShader_shadowmask_vp; -extern const char *fallbackShader_shadowmask_fp; -extern const char *fallbackShader_ssao_vp; -extern const char *fallbackShader_ssao_fp; -extern const char *fallbackShader_texturecolor_vp; -extern const char *fallbackShader_texturecolor_fp; -extern const char *fallbackShader_tonemap_vp; -extern const char *fallbackShader_tonemap_fp; - -typedef struct uniformInfo_s -{ - char *name; - int type; -} -uniformInfo_t; - -// These must be in the same order as in uniform_t in tr_local.h. -static uniformInfo_t uniformsInfo[] = -{ - { "u_DiffuseMap", GLSL_INT }, - { "u_LightMap", GLSL_INT }, - { "u_NormalMap", GLSL_INT }, - { "u_DeluxeMap", GLSL_INT }, - { "u_SpecularMap", GLSL_INT }, - - { "u_TextureMap", GLSL_INT }, - { "u_LevelsMap", GLSL_INT }, - { "u_CubeMap", GLSL_INT }, - - { "u_ScreenImageMap", GLSL_INT }, - { "u_ScreenDepthMap", GLSL_INT }, - - { "u_ShadowMap", GLSL_INT }, - { "u_ShadowMap2", GLSL_INT }, - { "u_ShadowMap3", GLSL_INT }, - - { "u_ShadowMvp", GLSL_MAT16 }, - { "u_ShadowMvp2", GLSL_MAT16 }, - { "u_ShadowMvp3", GLSL_MAT16 }, - - { "u_EnableTextures", GLSL_VEC4 }, - - { "u_DiffuseTexMatrix", GLSL_VEC4 }, - { "u_DiffuseTexOffTurb", GLSL_VEC4 }, - { "u_Texture1Env", GLSL_INT }, - - { "u_TCGen0", GLSL_INT }, - { "u_TCGen0Vector0", GLSL_VEC3 }, - { "u_TCGen0Vector1", GLSL_VEC3 }, - - { "u_DeformGen", GLSL_INT }, - { "u_DeformParams", GLSL_FLOAT5 }, - - { "u_ColorGen", GLSL_INT }, - { "u_AlphaGen", GLSL_INT }, - { "u_Color", GLSL_VEC4 }, - { "u_BaseColor", GLSL_VEC4 }, - { "u_VertColor", GLSL_VEC4 }, - - { "u_DlightInfo", GLSL_VEC4 }, - { "u_LightForward", GLSL_VEC3 }, - { "u_LightUp", GLSL_VEC3 }, - { "u_LightRight", GLSL_VEC3 }, - { "u_LightOrigin", GLSL_VEC4 }, - { "u_ModelLightDir", GLSL_VEC3 }, - { "u_LightRadius", GLSL_FLOAT }, - { "u_AmbientLight", GLSL_VEC3 }, - { "u_DirectedLight", GLSL_VEC3 }, - - { "u_PortalRange", GLSL_FLOAT }, - - { "u_FogDistance", GLSL_VEC4 }, - { "u_FogDepth", GLSL_VEC4 }, - { "u_FogEyeT", GLSL_FLOAT }, - { "u_FogColorMask", GLSL_VEC4 }, - - { "u_ModelMatrix", GLSL_MAT16 }, - { "u_ModelViewProjectionMatrix", GLSL_MAT16 }, - - { "u_Time", GLSL_FLOAT }, - { "u_VertexLerp" , GLSL_FLOAT }, - { "u_MaterialInfo", GLSL_VEC2 }, - - { "u_ViewInfo", GLSL_VEC4 }, - { "u_ViewOrigin", GLSL_VEC3 }, - { "u_LocalViewOrigin", GLSL_VEC3 }, - { "u_ViewForward", GLSL_VEC3 }, - { "u_ViewLeft", GLSL_VEC3 }, - { "u_ViewUp", GLSL_VEC3 }, - - { "u_InvTexRes", GLSL_VEC2 }, - { "u_AutoExposureMinMax", GLSL_VEC2 }, - { "u_ToneMinAvgMaxLinear", GLSL_VEC3 }, - - { "u_PrimaryLightOrigin", GLSL_VEC4 }, - { "u_PrimaryLightColor", GLSL_VEC3 }, - { "u_PrimaryLightAmbient", GLSL_VEC3 }, - { "u_PrimaryLightRadius", GLSL_FLOAT } -}; - - -static void GLSL_PrintInfoLog(GLhandleARB object, qboolean developerOnly) -{ - char *msg; - static char msgPart[1024]; - int maxLength = 0; - int i; - int printLevel = developerOnly ? PRINT_DEVELOPER : PRINT_ALL; - - qglGetObjectParameterivARB(object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength); - - if (maxLength <= 0) - { - ri.Printf(printLevel, "No compile log.\n"); - return; - } - - ri.Printf(printLevel, "compile log:\n"); - - if (maxLength < 1023) - { - qglGetInfoLogARB(object, maxLength, &maxLength, msgPart); - - msgPart[maxLength + 1] = '\0'; - - ri.Printf(printLevel, "%s\n", msgPart); - } - else - { - msg = ri.Malloc(maxLength); - - qglGetInfoLogARB(object, maxLength, &maxLength, msg); - - for(i = 0; i < maxLength; i += 1024) - { - Q_strncpyz(msgPart, msg + i, sizeof(msgPart)); - - ri.Printf(printLevel, "%s\n", msgPart); - } - - ri.Free(msg); - } -} - -static void GLSL_PrintShaderSource(GLhandleARB object) -{ - char *msg; - static char msgPart[1024]; - int maxLength = 0; - int i; - - qglGetObjectParameterivARB(object, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &maxLength); - - msg = ri.Malloc(maxLength); - - qglGetShaderSourceARB(object, maxLength, &maxLength, msg); - - for(i = 0; i < maxLength; i += 1024) - { - Q_strncpyz(msgPart, msg + i, sizeof(msgPart)); - ri.Printf(PRINT_ALL, "%s\n", msgPart); - } - - ri.Free(msg); -} - -static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, char *dest, int size ) -{ - float fbufWidthScale, fbufHeightScale; - - dest[0] = '\0'; - - // HACK: abuse the GLSL preprocessor to turn GLSL 1.20 shaders into 1.30 ones - if(glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 30)) - { - Q_strcat(dest, size, "#version 130\n"); - - if(shaderType == GL_VERTEX_SHADER_ARB) - { - Q_strcat(dest, size, "#define attribute in\n"); - Q_strcat(dest, size, "#define varying out\n"); - } - else - { - Q_strcat(dest, size, "#define varying in\n"); - - Q_strcat(dest, size, "out vec4 out_Color;\n"); - Q_strcat(dest, size, "#define gl_FragColor out_Color\n"); - } - } - else - { - Q_strcat(dest, size, "#version 120\n"); - } - - // HACK: add some macros to avoid extra uniforms and save speed and code maintenance - //Q_strcat(dest, size, - // va("#ifndef r_SpecularExponent\n#define r_SpecularExponent %f\n#endif\n", r_specularExponent->value)); - //Q_strcat(dest, size, - // va("#ifndef r_SpecularScale\n#define r_SpecularScale %f\n#endif\n", r_specularScale->value)); - //Q_strcat(dest, size, - // va("#ifndef r_NormalScale\n#define r_NormalScale %f\n#endif\n", r_normalScale->value)); - - - Q_strcat(dest, size, "#ifndef M_PI\n#define M_PI 3.14159265358979323846f\n#endif\n"); - - //Q_strcat(dest, size, va("#ifndef MAX_SHADOWMAPS\n#define MAX_SHADOWMAPS %i\n#endif\n", MAX_SHADOWMAPS)); - - Q_strcat(dest, size, - va("#ifndef deformGen_t\n" - "#define deformGen_t\n" - "#define DGEN_WAVE_SIN %i\n" - "#define DGEN_WAVE_SQUARE %i\n" - "#define DGEN_WAVE_TRIANGLE %i\n" - "#define DGEN_WAVE_SAWTOOTH %i\n" - "#define DGEN_WAVE_INVERSE_SAWTOOTH %i\n" - "#define DGEN_BULGE %i\n" - "#define DGEN_MOVE %i\n" - "#endif\n", - DGEN_WAVE_SIN, - DGEN_WAVE_SQUARE, - DGEN_WAVE_TRIANGLE, - DGEN_WAVE_SAWTOOTH, - DGEN_WAVE_INVERSE_SAWTOOTH, - DGEN_BULGE, - DGEN_MOVE)); - - Q_strcat(dest, size, - va("#ifndef tcGen_t\n" - "#define tcGen_t\n" - "#define TCGEN_LIGHTMAP %i\n" - "#define TCGEN_TEXTURE %i\n" - "#define TCGEN_ENVIRONMENT_MAPPED %i\n" - "#define TCGEN_FOG %i\n" - "#define TCGEN_VECTOR %i\n" - "#endif\n", - TCGEN_LIGHTMAP, - TCGEN_TEXTURE, - TCGEN_ENVIRONMENT_MAPPED, - TCGEN_FOG, - TCGEN_VECTOR)); - - Q_strcat(dest, size, - va("#ifndef colorGen_t\n" - "#define colorGen_t\n" - "#define CGEN_LIGHTING_DIFFUSE %i\n" - "#endif\n", - CGEN_LIGHTING_DIFFUSE)); - - Q_strcat(dest, size, - va("#ifndef alphaGen_t\n" - "#define alphaGen_t\n" - "#define AGEN_LIGHTING_SPECULAR %i\n" - "#define AGEN_PORTAL %i\n" - "#endif\n", - AGEN_LIGHTING_SPECULAR, - AGEN_PORTAL)); - - Q_strcat(dest, size, - va("#ifndef texenv_t\n" - "#define texenv_t\n" - "#define TEXENV_MODULATE %i\n" - "#define TEXENV_ADD %i\n" - "#define TEXENV_REPLACE %i\n" - "#endif\n", - GL_MODULATE, - GL_ADD, - GL_REPLACE)); - - fbufWidthScale = 1.0f / ((float)glConfig.vidWidth); - fbufHeightScale = 1.0f / ((float)glConfig.vidHeight); - Q_strcat(dest, size, - va("#ifndef r_FBufScale\n#define r_FBufScale vec2(%f, %f)\n#endif\n", fbufWidthScale, fbufHeightScale)); - - if (extra) - { - Q_strcat(dest, size, extra); - } - - // OK we added a lot of stuff but if we do something bad in the GLSL shaders then we want the proper line - // so we have to reset the line counting - Q_strcat(dest, size, "#line 0\n"); -} - -static int GLSL_CompileGPUShader(GLhandleARB program, GLhandleARB *prevShader, const GLcharARB *buffer, int size, GLenum shaderType) -{ - GLint compiled; - GLhandleARB shader; - - shader = qglCreateShaderObjectARB(shaderType); - - qglShaderSourceARB(shader, 1, (const GLcharARB **)&buffer, &size); - - // compile shader - qglCompileShaderARB(shader); - - // check if shader compiled - qglGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled); - if(!compiled) - { - GLSL_PrintShaderSource(shader); - GLSL_PrintInfoLog(shader, qfalse); - ri.Error(ERR_DROP, "Couldn't compile shader"); - return 0; - } - - //GLSL_PrintInfoLog(shader, qtrue); - //GLSL_PrintShaderSource(shader); - - if (*prevShader) - { - qglDetachObjectARB(program, *prevShader); - qglDeleteObjectARB(*prevShader); - } - - // attach shader to program - qglAttachObjectARB(program, shader); - - *prevShader = shader; - - return 1; -} - -static int GLSL_LoadGPUShaderText(const char *name, const char *fallback, - GLenum shaderType, char *dest, int destSize) -{ - char filename[MAX_QPATH]; - GLcharARB *buffer = NULL; - const GLcharARB *shaderText = NULL; - int size; - int result; - - if(shaderType == GL_VERTEX_SHADER_ARB) - { - Com_sprintf(filename, sizeof(filename), "glsl/%s_vp.glsl", name); - } - else - { - Com_sprintf(filename, sizeof(filename), "glsl/%s_fp.glsl", name); - } - - ri.Printf(PRINT_DEVELOPER, "...loading '%s'\n", filename); - size = ri.FS_ReadFile(filename, (void **)&buffer); - if(!buffer) - { - if (fallback) - { - ri.Printf(PRINT_DEVELOPER, "couldn't load, using fallback\n"); - shaderText = fallback; - size = strlen(shaderText); - } - else - { - ri.Printf(PRINT_DEVELOPER, "couldn't load!\n"); - return 0; - } - } - else - { - shaderText = buffer; - } - - if (size > destSize) - { - result = 0; - } - else - { - Q_strncpyz(dest, shaderText, size + 1); - result = 1; - } - - if (buffer) - { - ri.FS_FreeFile(buffer); - } - - return result; -} - -static void GLSL_LinkProgram(GLhandleARB program) -{ - GLint linked; - - qglLinkProgramARB(program); - - qglGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linked); - if(!linked) - { - GLSL_PrintInfoLog(program, qfalse); - ri.Printf(PRINT_ALL, "\n"); - ri.Error(ERR_DROP, "shaders failed to link"); - } -} - -static void GLSL_ValidateProgram(GLhandleARB program) -{ - GLint validated; - - qglValidateProgramARB(program); - - qglGetObjectParameterivARB(program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated); - if(!validated) - { - GLSL_PrintInfoLog(program, qfalse); - ri.Printf(PRINT_ALL, "\n"); - ri.Error(ERR_DROP, "shaders failed to validate"); - } -} - -static void GLSL_ShowProgramUniforms(GLhandleARB program) -{ - int i, count, size; - GLenum type; - char uniformName[1000]; - - // install the executables in the program object as part of current state. - qglUseProgramObjectARB(program); - - // check for GL Errors - - // query the number of active uniforms - qglGetObjectParameterivARB(program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count); - - // Loop over each of the active uniforms, and set their value - for(i = 0; i < count; i++) - { - qglGetActiveUniformARB(program, i, sizeof(uniformName), NULL, &size, &type, uniformName); - - ri.Printf(PRINT_DEVELOPER, "active uniform: '%s'\n", uniformName); - } - - qglUseProgramObjectARB(0); -} - -static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int attribs, const char *vpCode, const char *fpCode) -{ - ri.Printf(PRINT_DEVELOPER, "------- GPU shader -------\n"); - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "GLSL_InitGPUShader2: \"%s\" is too long", name); - } - - Q_strncpyz(program->name, name, sizeof(program->name)); - - program->program = qglCreateProgramObjectARB(); - program->attribs = attribs; - - if (!(GLSL_CompileGPUShader(program->program, &program->vertexShader, vpCode, strlen(vpCode), GL_VERTEX_SHADER_ARB))) - { - ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_VERTEX_SHADER_ARB\n", name); - qglDeleteObjectARB(program->program); - return 0; - } - - if(fpCode) - { - if(!(GLSL_CompileGPUShader(program->program, &program->fragmentShader, fpCode, strlen(fpCode), GL_FRAGMENT_SHADER_ARB))) - { - ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_FRAGMENT_SHADER_ARB\n", name); - qglDeleteObjectARB(program->program); - return 0; - } - } - - if(attribs & ATTR_POSITION) - qglBindAttribLocationARB(program->program, ATTR_INDEX_POSITION, "attr_Position"); - - if(attribs & ATTR_TEXCOORD) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD0, "attr_TexCoord0"); - - if(attribs & ATTR_LIGHTCOORD) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD1, "attr_TexCoord1"); - -// if(attribs & ATTR_TEXCOORD2) -// qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD2, "attr_TexCoord2"); - -// if(attribs & ATTR_TEXCOORD3) -// qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD3, "attr_TexCoord3"); - -#ifdef USE_VERT_TANGENT_SPACE - if(attribs & ATTR_TANGENT) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TANGENT, "attr_Tangent"); -#endif - - if(attribs & ATTR_NORMAL) - qglBindAttribLocationARB(program->program, ATTR_INDEX_NORMAL, "attr_Normal"); - - if(attribs & ATTR_COLOR) - qglBindAttribLocationARB(program->program, ATTR_INDEX_COLOR, "attr_Color"); - - if(attribs & ATTR_PAINTCOLOR) - qglBindAttribLocationARB(program->program, ATTR_INDEX_PAINTCOLOR, "attr_PaintColor"); - - if(attribs & ATTR_LIGHTDIRECTION) - qglBindAttribLocationARB(program->program, ATTR_INDEX_LIGHTDIRECTION, "attr_LightDirection"); - - if(attribs & ATTR_POSITION2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_POSITION2, "attr_Position2"); - - if(attribs & ATTR_NORMAL2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_NORMAL2, "attr_Normal2"); - -#ifdef USE_VERT_TANGENT_SPACE - if(attribs & ATTR_TANGENT2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TANGENT2, "attr_Tangent2"); -#endif - - GLSL_LinkProgram(program->program); - - return 1; -} - -static int GLSL_InitGPUShader(shaderProgram_t * program, const char *name, - int attribs, qboolean fragmentShader, const GLcharARB *extra, qboolean addHeader, - const char *fallback_vp, const char *fallback_fp) -{ - char vpCode[32000]; - char fpCode[32000]; - char *postHeader; - int size; - int result; - - size = sizeof(vpCode); - if (addHeader) - { - GLSL_GetShaderHeader(GL_VERTEX_SHADER_ARB, extra, vpCode, size); - postHeader = &vpCode[strlen(vpCode)]; - size -= strlen(vpCode); - } - else - { - postHeader = &vpCode[0]; - } - - if (!GLSL_LoadGPUShaderText(name, fallback_vp, GL_VERTEX_SHADER_ARB, postHeader, size)) - { - return 0; - } - - if (fragmentShader) - { - size = sizeof(fpCode); - if (addHeader) - { - GLSL_GetShaderHeader(GL_FRAGMENT_SHADER_ARB, extra, fpCode, size); - postHeader = &fpCode[strlen(fpCode)]; - size -= strlen(fpCode); - } - else - { - postHeader = &fpCode[0]; - } - - if (!GLSL_LoadGPUShaderText(name, fallback_fp, GL_FRAGMENT_SHADER_ARB, postHeader, size)) - { - return 0; - } - } - - result = GLSL_InitGPUShader2(program, name, attribs, vpCode, fragmentShader ? fpCode : NULL); - - return result; -} - -void GLSL_InitUniforms(shaderProgram_t *program) -{ - int i, size; - - GLint *uniforms = program->uniforms; - - size = 0; - for (i = 0; i < UNIFORM_COUNT; i++) - { - uniforms[i] = qglGetUniformLocationARB(program->program, uniformsInfo[i].name); - - if (uniforms[i] == -1) - continue; - - program->uniformBufferOffsets[i] = size; - - switch(uniformsInfo[i].type) - { - case GLSL_INT: - size += sizeof(GLint); - break; - case GLSL_FLOAT: - size += sizeof(GLfloat); - break; - case GLSL_FLOAT5: - size += sizeof(vec_t) * 5; - break; - case GLSL_VEC2: - size += sizeof(vec_t) * 2; - break; - case GLSL_VEC3: - size += sizeof(vec_t) * 3; - break; - case GLSL_VEC4: - size += sizeof(vec_t) * 4; - break; - case GLSL_MAT16: - size += sizeof(vec_t) * 16; - break; - default: - break; - } - } - - program->uniformBuffer = ri.Malloc(size); -} - -void GLSL_FinishGPUShader(shaderProgram_t *program) -{ - GLSL_ValidateProgram(program->program); - GLSL_ShowProgramUniforms(program->program); - GL_CheckErrors(); -} - -void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value) -{ - GLint *uniforms = program->uniforms; - GLint *compare = (GLint *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_INT) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformInt: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (value == *compare) - { - return; - } - - *compare = value; - - qglUniform1iARB(uniforms[uniformNum], value); -} - -void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value) -{ - GLint *uniforms = program->uniforms; - GLfloat *compare = (GLfloat *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_FLOAT) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformFloat: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (value == *compare) - { - return; - } - - *compare = value; - - qglUniform1fARB(uniforms[uniformNum], value); -} - -void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_VEC2) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec2: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (v[0] == compare[0] && v[1] == compare[1]) - { - return; - } - - compare[0] = v[0]; - compare[1] = v[1]; - - qglUniform2fARB(uniforms[uniformNum], v[0], v[1]); -} - -void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_VEC3) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec3: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (VectorCompare(v, compare)) - { - return; - } - - VectorCopy(v, compare); - - qglUniform3fARB(uniforms[uniformNum], v[0], v[1], v[2]); -} - -void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_VEC4) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec4: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (VectorCompare4(v, compare)) - { - return; - } - - VectorCopy4(v, compare); - - qglUniform4fARB(uniforms[uniformNum], v[0], v[1], v[2], v[3]); -} - -void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_FLOAT5) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformFloat5: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (VectorCompare5(v, compare)) - { - return; - } - - VectorCopy5(v, compare); - - qglUniform1fvARB(uniforms[uniformNum], 5, v); -} - -void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_MAT16) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (Mat4Compare(matrix, compare)) - { - return; - } - - Mat4Copy(matrix, compare); - - qglUniformMatrix4fvARB(uniforms[uniformNum], 1, GL_FALSE, matrix); -} - -void GLSL_DeleteGPUShader(shaderProgram_t *program) -{ - if(program->program) - { - if (program->vertexShader) - { - qglDetachObjectARB(program->program, program->vertexShader); - qglDeleteObjectARB(program->vertexShader); - } - - if (program->fragmentShader) - { - qglDetachObjectARB(program->program, program->fragmentShader); - qglDeleteObjectARB(program->fragmentShader); - } - - qglDeleteObjectARB(program->program); - - if (program->uniformBuffer) - { - ri.Free(program->uniformBuffer); - } - - Com_Memset(program, 0, sizeof(*program)); - } -} - -void GLSL_InitGPUShaders(void) -{ - int startTime, endTime; - int i; - char extradefines[1024]; - int attribs; - int numGenShaders = 0, numLightShaders = 0, numEtcShaders = 0; - - ri.Printf(PRINT_ALL, "------- GLSL_InitGPUShaders -------\n"); - - R_IssuePendingRenderCommands(); - - startTime = ri.Milliseconds(); - - for (i = 0; i < GENERICDEF_COUNT; i++) - { - attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_NORMAL | ATTR_COLOR; - extradefines[0] = '\0'; - - if (i & GENERICDEF_USE_DEFORM_VERTEXES) - Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n"); - - if (i & GENERICDEF_USE_TCGEN_AND_TCMOD) - { - Q_strcat(extradefines, 1024, "#define USE_TCGEN\n"); - Q_strcat(extradefines, 1024, "#define USE_TCMOD\n"); - } - - if (i & GENERICDEF_USE_VERTEX_ANIMATION) - { - Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n"); - attribs |= ATTR_POSITION2 | ATTR_NORMAL2; - } - - if (i & GENERICDEF_USE_FOG) - Q_strcat(extradefines, 1024, "#define USE_FOG\n"); - - if (i & GENERICDEF_USE_RGBAGEN) - Q_strcat(extradefines, 1024, "#define USE_RGBAGEN\n"); - - if (i & GENERICDEF_USE_LIGHTMAP) - Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n"); - - if (r_hdr->integer && !(glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer)) - Q_strcat(extradefines, 1024, "#define RGBM_LIGHTMAP\n"); - - if (!GLSL_InitGPUShader(&tr.genericShader[i], "generic", attribs, qtrue, extradefines, qtrue, fallbackShader_generic_vp, fallbackShader_generic_fp)) - { - ri.Error(ERR_FATAL, "Could not load generic shader!"); - } - - GLSL_InitUniforms(&tr.genericShader[i]); - - qglUseProgramObjectARB(tr.genericShader[i].program); - GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.genericShader[i]); - - numGenShaders++; - } - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - - if (!GLSL_InitGPUShader(&tr.textureColorShader, "texturecolor", attribs, qtrue, NULL, qfalse, fallbackShader_texturecolor_vp, fallbackShader_texturecolor_fp)) - { - ri.Error(ERR_FATAL, "Could not load texturecolor shader!"); - } - - GLSL_InitUniforms(&tr.textureColorShader); - - qglUseProgramObjectARB(tr.textureColorShader.program); - GLSL_SetUniformInt(&tr.textureColorShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.textureColorShader); - - numEtcShaders++; - - for (i = 0; i < FOGDEF_COUNT; i++) - { - attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (i & FOGDEF_USE_DEFORM_VERTEXES) - Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n"); - - if (i & FOGDEF_USE_VERTEX_ANIMATION) - Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n"); - - if (!GLSL_InitGPUShader(&tr.fogShader[i], "fogpass", attribs, qtrue, extradefines, qtrue, fallbackShader_fogpass_vp, fallbackShader_fogpass_fp)) - { - ri.Error(ERR_FATAL, "Could not load fogpass shader!"); - } - - GLSL_InitUniforms(&tr.fogShader[i]); - GLSL_FinishGPUShader(&tr.fogShader[i]); - - numEtcShaders++; - } - - - for (i = 0; i < DLIGHTDEF_COUNT; i++) - { - attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (i & DLIGHTDEF_USE_DEFORM_VERTEXES) - { - Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n"); - } - - if (!GLSL_InitGPUShader(&tr.dlightShader[i], "dlight", attribs, qtrue, extradefines, qtrue, fallbackShader_dlight_vp, fallbackShader_dlight_fp)) - { - ri.Error(ERR_FATAL, "Could not load dlight shader!"); - } - - GLSL_InitUniforms(&tr.dlightShader[i]); - - qglUseProgramObjectARB(tr.dlightShader[i].program); - GLSL_SetUniformInt(&tr.dlightShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.dlightShader[i]); - - numEtcShaders++; - } - - - for (i = 0; i < LIGHTDEF_COUNT; i++) - { - int lightType = i & LIGHTDEF_LIGHTTYPE_MASK; - qboolean fastLight = !(r_normalMapping->integer || r_specularMapping->integer); - - // skip impossible combos - if ((i & LIGHTDEF_USE_PARALLAXMAP) && !r_parallaxMapping->integer) - continue; - - if (!lightType && (i & LIGHTDEF_USE_PARALLAXMAP)) - continue; - - if (!lightType && (i & LIGHTDEF_USE_SHADOWMAP)) - continue; - - attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL; - - extradefines[0] = '\0'; - - if (r_deluxeSpecular->value > 0.000001f) - Q_strcat(extradefines, 1024, va("#define r_deluxeSpecular %f\n", r_deluxeSpecular->value)); - - if (r_specularIsMetallic->value) - Q_strcat(extradefines, 1024, "#define SPECULAR_IS_METALLIC\n"); - - if (r_dlightMode->integer >= 2) - Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n"); - - if (1) - Q_strcat(extradefines, 1024, "#define SWIZZLE_NORMALMAP\n"); - - if (r_hdr->integer && !(glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer)) - Q_strcat(extradefines, 1024, "#define RGBM_LIGHTMAP\n"); - - if (lightType) - { - Q_strcat(extradefines, 1024, "#define USE_LIGHT\n"); - - if (fastLight) - Q_strcat(extradefines, 1024, "#define USE_FAST_LIGHT\n"); - - switch (lightType) - { - case LIGHTDEF_USE_LIGHTMAP: - Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n"); - if (r_deluxeMapping->integer && !fastLight) - Q_strcat(extradefines, 1024, "#define USE_DELUXEMAP\n"); - attribs |= ATTR_LIGHTCOORD | ATTR_LIGHTDIRECTION; - break; - case LIGHTDEF_USE_LIGHT_VECTOR: - Q_strcat(extradefines, 1024, "#define USE_LIGHT_VECTOR\n"); - break; - case LIGHTDEF_USE_LIGHT_VERTEX: - Q_strcat(extradefines, 1024, "#define USE_LIGHT_VERTEX\n"); - attribs |= ATTR_LIGHTDIRECTION; - break; - default: - break; - } - - if (r_normalMapping->integer) - { - Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n"); - - if (r_normalMapping->integer == 2) - Q_strcat(extradefines, 1024, "#define USE_OREN_NAYAR\n"); - - if (r_normalMapping->integer == 3) - Q_strcat(extradefines, 1024, "#define USE_TRIACE_OREN_NAYAR\n"); - -#ifdef USE_VERT_TANGENT_SPACE - Q_strcat(extradefines, 1024, "#define USE_VERT_TANGENT_SPACE\n"); - attribs |= ATTR_TANGENT; -#endif - - if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer) - Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n"); - } - - if (r_specularMapping->integer) - { - Q_strcat(extradefines, 1024, "#define USE_SPECULARMAP\n"); - - switch (r_specularMapping->integer) - { - case 1: - default: - Q_strcat(extradefines, 1024, "#define USE_BLINN\n"); - break; - - case 2: - Q_strcat(extradefines, 1024, "#define USE_BLINN_FRESNEL\n"); - break; - - case 3: - Q_strcat(extradefines, 1024, "#define USE_MCAULEY\n"); - break; - - case 4: - Q_strcat(extradefines, 1024, "#define USE_GOTANDA\n"); - break; - - case 5: - Q_strcat(extradefines, 1024, "#define USE_LAZAROV\n"); - break; - } - } - - if (r_cubeMapping->integer) - Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n"); - } - - if (i & LIGHTDEF_USE_SHADOWMAP) - { - Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n"); - - if (r_sunlightMode->integer == 1) - Q_strcat(extradefines, 1024, "#define SHADOWMAP_MODULATE\n"); - else if (r_sunlightMode->integer == 2) - Q_strcat(extradefines, 1024, "#define USE_PRIMARY_LIGHT\n"); - } - - if (i & LIGHTDEF_USE_TCGEN_AND_TCMOD) - { - Q_strcat(extradefines, 1024, "#define USE_TCGEN\n"); - Q_strcat(extradefines, 1024, "#define USE_TCMOD\n"); - } - - if (i & LIGHTDEF_ENTITY) - { - Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n#define USE_MODELMATRIX\n"); - attribs |= ATTR_POSITION2 | ATTR_NORMAL2; - -#ifdef USE_VERT_TANGENT_SPACE - if (r_normalMapping->integer) - { - attribs |= ATTR_TANGENT2; - } -#endif - } - - if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, qtrue, extradefines, qtrue, fallbackShader_lightall_vp, fallbackShader_lightall_fp)) - { - ri.Error(ERR_FATAL, "Could not load lightall shader!"); - } - - GLSL_InitUniforms(&tr.lightallShader[i]); - - qglUseProgramObjectARB(tr.lightallShader[i].program); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_NORMALMAP, TB_NORMALMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DELUXEMAP, TB_DELUXEMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SPECULARMAP, TB_SPECULARMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SHADOWMAP, TB_SHADOWMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_CUBEMAP, TB_CUBEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.lightallShader[i]); - - numLightShaders++; - } - - attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD; - - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp)) - { - ri.Error(ERR_FATAL, "Could not load shadowfill shader!"); - } - - GLSL_InitUniforms(&tr.shadowmapShader); - GLSL_FinishGPUShader(&tr.shadowmapShader); - - numEtcShaders++; - - attribs = ATTR_POSITION | ATTR_NORMAL; - extradefines[0] = '\0'; - - Q_strcat(extradefines, 1024, "#define USE_PCF\n#define USE_DISCARD\n"); - - if (!GLSL_InitGPUShader(&tr.pshadowShader, "pshadow", attribs, qtrue, extradefines, qtrue, fallbackShader_pshadow_vp, fallbackShader_pshadow_fp)) - { - ri.Error(ERR_FATAL, "Could not load pshadow shader!"); - } - - GLSL_InitUniforms(&tr.pshadowShader); - - qglUseProgramObjectARB(tr.pshadowShader.program); - GLSL_SetUniformInt(&tr.pshadowShader, UNIFORM_SHADOWMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.pshadowShader); - - numEtcShaders++; - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.down4xShader, "down4x", attribs, qtrue, extradefines, qtrue, fallbackShader_down4x_vp, fallbackShader_down4x_fp)) - { - ri.Error(ERR_FATAL, "Could not load down4x shader!"); - } - - GLSL_InitUniforms(&tr.down4xShader); - - qglUseProgramObjectARB(tr.down4xShader.program); - GLSL_SetUniformInt(&tr.down4xShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.down4xShader); - - numEtcShaders++; - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.bokehShader, "bokeh", attribs, qtrue, extradefines, qtrue, fallbackShader_bokeh_vp, fallbackShader_bokeh_fp)) - { - ri.Error(ERR_FATAL, "Could not load bokeh shader!"); - } - - GLSL_InitUniforms(&tr.bokehShader); - - qglUseProgramObjectARB(tr.bokehShader.program); - GLSL_SetUniformInt(&tr.bokehShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.bokehShader); - - numEtcShaders++; - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.tonemapShader, "tonemap", attribs, qtrue, extradefines, qtrue, fallbackShader_tonemap_vp, fallbackShader_tonemap_fp)) - { - ri.Error(ERR_FATAL, "Could not load tonemap shader!"); - } - - GLSL_InitUniforms(&tr.tonemapShader); - - qglUseProgramObjectARB(tr.tonemapShader.program); - GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_TEXTUREMAP, TB_COLORMAP); - GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_LEVELSMAP, TB_LEVELSMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.tonemapShader); - - numEtcShaders++; - - - for (i = 0; i < 2; i++) - { - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!i) - Q_strcat(extradefines, 1024, "#define FIRST_PASS\n"); - - if (!GLSL_InitGPUShader(&tr.calclevels4xShader[i], "calclevels4x", attribs, qtrue, extradefines, qtrue, fallbackShader_calclevels4x_vp, fallbackShader_calclevels4x_fp)) - { - ri.Error(ERR_FATAL, "Could not load calclevels4x shader!"); - } - - GLSL_InitUniforms(&tr.calclevels4xShader[i]); - - qglUseProgramObjectARB(tr.calclevels4xShader[i].program); - GLSL_SetUniformInt(&tr.calclevels4xShader[i], UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.calclevels4xShader[i]); - - numEtcShaders++; - } - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (r_shadowFilter->integer >= 1) - Q_strcat(extradefines, 1024, "#define USE_SHADOW_FILTER\n"); - - if (r_shadowFilter->integer >= 2) - Q_strcat(extradefines, 1024, "#define USE_SHADOW_FILTER2\n"); - - Q_strcat(extradefines, 1024, "#define USE_SHADOW_CASCADE\n"); - - Q_strcat(extradefines, 1024, va("#define r_shadowMapSize %d\n", r_shadowMapSize->integer)); - Q_strcat(extradefines, 1024, va("#define r_shadowCascadeZFar %f\n", r_shadowCascadeZFar->value)); - - - if (!GLSL_InitGPUShader(&tr.shadowmaskShader, "shadowmask", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowmask_vp, fallbackShader_shadowmask_fp)) - { - ri.Error(ERR_FATAL, "Could not load shadowmask shader!"); - } - - GLSL_InitUniforms(&tr.shadowmaskShader); - - qglUseProgramObjectARB(tr.shadowmaskShader.program); - GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP); - GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP, TB_SHADOWMAP); - GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP2, TB_SHADOWMAP2); - GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP3, TB_SHADOWMAP3); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.shadowmaskShader); - - numEtcShaders++; - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.ssaoShader, "ssao", attribs, qtrue, extradefines, qtrue, fallbackShader_ssao_vp, fallbackShader_ssao_fp)) - { - ri.Error(ERR_FATAL, "Could not load ssao shader!"); - } - - GLSL_InitUniforms(&tr.ssaoShader); - - qglUseProgramObjectARB(tr.ssaoShader.program); - GLSL_SetUniformInt(&tr.ssaoShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.ssaoShader); - - numEtcShaders++; - - - for (i = 0; i < 2; i++) - { - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (i & 1) - Q_strcat(extradefines, 1024, "#define USE_VERTICAL_BLUR\n"); - else - Q_strcat(extradefines, 1024, "#define USE_HORIZONTAL_BLUR\n"); - - - if (!GLSL_InitGPUShader(&tr.depthBlurShader[i], "depthBlur", attribs, qtrue, extradefines, qtrue, fallbackShader_depthblur_vp, fallbackShader_depthblur_fp)) - { - ri.Error(ERR_FATAL, "Could not load depthBlur shader!"); - } - - GLSL_InitUniforms(&tr.depthBlurShader[i]); - - qglUseProgramObjectARB(tr.depthBlurShader[i].program); - GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENIMAGEMAP, TB_COLORMAP); - GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENDEPTHMAP, TB_LIGHTMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.depthBlurShader[i]); - - numEtcShaders++; - } - -#if 0 - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.testcubeShader, "testcube", attribs, qtrue, extradefines, qtrue, NULL, NULL)) - { - ri.Error(ERR_FATAL, "Could not load testcube shader!"); - } - - GLSL_InitUniforms(&tr.testcubeShader); - - qglUseProgramObjectARB(tr.testcubeShader.program); - GLSL_SetUniformInt(&tr.testcubeShader, UNIFORM_TEXTUREMAP, TB_COLORMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.testcubeShader); - - numEtcShaders++; -#endif - - - endTime = ri.Milliseconds(); - - ri.Printf(PRINT_ALL, "loaded %i GLSL shaders (%i gen %i light %i etc) in %5.2f seconds\n", - numGenShaders + numLightShaders + numEtcShaders, numGenShaders, numLightShaders, - numEtcShaders, (endTime - startTime) / 1000.0); -} - -void GLSL_ShutdownGPUShaders(void) -{ - int i; - - ri.Printf(PRINT_ALL, "------- GLSL_ShutdownGPUShaders -------\n"); - - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD0); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD1); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION2); - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL); -#ifdef USE_VERT_TANGENT_SPACE - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT); -#endif - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL2); -#ifdef USE_VERT_TANGENT_SPACE - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT2); -#endif - qglDisableVertexAttribArrayARB(ATTR_INDEX_COLOR); - qglDisableVertexAttribArrayARB(ATTR_INDEX_LIGHTDIRECTION); - GLSL_BindNullProgram(); - - for ( i = 0; i < GENERICDEF_COUNT; i++) - GLSL_DeleteGPUShader(&tr.genericShader[i]); - - GLSL_DeleteGPUShader(&tr.textureColorShader); - - for ( i = 0; i < FOGDEF_COUNT; i++) - GLSL_DeleteGPUShader(&tr.fogShader[i]); - - for ( i = 0; i < DLIGHTDEF_COUNT; i++) - GLSL_DeleteGPUShader(&tr.dlightShader[i]); - - for ( i = 0; i < LIGHTDEF_COUNT; i++) - GLSL_DeleteGPUShader(&tr.lightallShader[i]); - - GLSL_DeleteGPUShader(&tr.shadowmapShader); - GLSL_DeleteGPUShader(&tr.pshadowShader); - GLSL_DeleteGPUShader(&tr.down4xShader); - GLSL_DeleteGPUShader(&tr.bokehShader); - GLSL_DeleteGPUShader(&tr.tonemapShader); - - for ( i = 0; i < 2; i++) - GLSL_DeleteGPUShader(&tr.calclevels4xShader[i]); - - GLSL_DeleteGPUShader(&tr.shadowmaskShader); - GLSL_DeleteGPUShader(&tr.ssaoShader); - - for ( i = 0; i < 2; i++) - GLSL_DeleteGPUShader(&tr.depthBlurShader[i]); - - glState.currentProgram = 0; - qglUseProgramObjectARB(0); -} - - -void GLSL_BindProgram(shaderProgram_t * program) -{ - if(!program) - { - GLSL_BindNullProgram(); - return; - } - - if(r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- GL_BindProgram( %s ) ---\n", program->name)); - } - - if(glState.currentProgram != program) - { - qglUseProgramObjectARB(program->program); - glState.currentProgram = program; - backEnd.pc.c_glslShaderBinds++; - } -} - - -void GLSL_BindNullProgram(void) -{ - if(r_logFile->integer) - { - GLimp_LogComment("--- GL_BindNullProgram ---\n"); - } - - if(glState.currentProgram) - { - qglUseProgramObjectARB(0); - glState.currentProgram = NULL; - } -} - - -void GLSL_VertexAttribsState(uint32_t stateBits) -{ - uint32_t diff; - - GLSL_VertexAttribPointers(stateBits); - - diff = stateBits ^ glState.vertexAttribsState; - if(!diff) - { - return; - } - - if(diff & ATTR_POSITION) - { - if(stateBits & ATTR_POSITION) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_POSITION )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_POSITION); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_POSITION )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION); - } - } - - if(diff & ATTR_TEXCOORD) - { - if(stateBits & ATTR_TEXCOORD) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_TEXCOORD )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD0); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_TEXCOORD )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD0); - } - } - - if(diff & ATTR_LIGHTCOORD) - { - if(stateBits & ATTR_LIGHTCOORD) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_LIGHTCOORD )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD1); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_LIGHTCOORD )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD1); - } - } - - if(diff & ATTR_NORMAL) - { - if(stateBits & ATTR_NORMAL) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_NORMAL )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_NORMAL); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_NORMAL )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL); - } - } - -#ifdef USE_VERT_TANGENT_SPACE - if(diff & ATTR_TANGENT) - { - if(stateBits & ATTR_TANGENT) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_TANGENT )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TANGENT); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_TANGENT )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT); - } - } -#endif - - if(diff & ATTR_COLOR) - { - if(stateBits & ATTR_COLOR) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_COLOR )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_COLOR); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_COLOR )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_COLOR); - } - } - - if(diff & ATTR_LIGHTDIRECTION) - { - if(stateBits & ATTR_LIGHTDIRECTION) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_LIGHTDIRECTION )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_LIGHTDIRECTION); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_LIGHTDIRECTION )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_LIGHTDIRECTION); - } - } - - if(diff & ATTR_POSITION2) - { - if(stateBits & ATTR_POSITION2) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_POSITION2 )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_POSITION2); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_POSITION2 )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION2); - } - } - - if(diff & ATTR_NORMAL2) - { - if(stateBits & ATTR_NORMAL2) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_NORMAL2 )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_NORMAL2); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_NORMAL2 )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL2); - } - } - -#ifdef USE_VERT_TANGENT_SPACE - if(diff & ATTR_TANGENT2) - { - if(stateBits & ATTR_TANGENT2) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_TANGENT2 )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TANGENT2); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_TANGENT2 )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT2); - } - } -#endif - - glState.vertexAttribsState = stateBits; -} - -void GLSL_VertexAttribPointers(uint32_t attribBits) -{ - qboolean animated; - int newFrame, oldFrame; - VBO_t *vbo = glState.currentVBO; - - if(!vbo) - { - ri.Error(ERR_FATAL, "GL_VertexAttribPointers: no VBO bound"); - return; - } - - // don't just call LogComment, or we will get a call to va() every frame! - if(r_logFile->integer) - { - GLimp_LogComment(va("--- GL_VertexAttribPointers( %s ) ---\n", vbo->name)); - } - - // position/normal/tangent are always set in case of animation - oldFrame = glState.vertexAttribsOldFrame; - newFrame = glState.vertexAttribsNewFrame; - animated = glState.vertexAnimation; - - if((attribBits & ATTR_POSITION) && (!(glState.vertexAttribPointersSet & ATTR_POSITION) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_POSITION )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_POSITION, 3, GL_FLOAT, 0, vbo->stride_xyz, BUFFER_OFFSET(vbo->ofs_xyz + newFrame * vbo->size_xyz)); - glState.vertexAttribPointersSet |= ATTR_POSITION; - } - - if((attribBits & ATTR_TEXCOORD) && !(glState.vertexAttribPointersSet & ATTR_TEXCOORD)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TEXCOORD )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TEXCOORD0, 2, GL_FLOAT, 0, vbo->stride_st, BUFFER_OFFSET(vbo->ofs_st)); - glState.vertexAttribPointersSet |= ATTR_TEXCOORD; - } - - if((attribBits & ATTR_LIGHTCOORD) && !(glState.vertexAttribPointersSet & ATTR_LIGHTCOORD)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_LIGHTCOORD )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TEXCOORD1, 2, GL_FLOAT, 0, vbo->stride_lightmap, BUFFER_OFFSET(vbo->ofs_lightmap)); - glState.vertexAttribPointersSet |= ATTR_LIGHTCOORD; - } - - if((attribBits & ATTR_NORMAL) && (!(glState.vertexAttribPointersSet & ATTR_NORMAL) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_NORMAL )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_NORMAL, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_normal, BUFFER_OFFSET(vbo->ofs_normal + newFrame * vbo->size_normal)); - glState.vertexAttribPointersSet |= ATTR_NORMAL; - } - -#ifdef USE_VERT_TANGENT_SPACE - if((attribBits & ATTR_TANGENT) && (!(glState.vertexAttribPointersSet & ATTR_TANGENT) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TANGENT )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TANGENT, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_tangent, BUFFER_OFFSET(vbo->ofs_tangent + newFrame * vbo->size_normal)); // FIXME - glState.vertexAttribPointersSet |= ATTR_TANGENT; - } -#endif - - if((attribBits & ATTR_COLOR) && !(glState.vertexAttribPointersSet & ATTR_COLOR)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_COLOR )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_COLOR, 4, GL_FLOAT, 0, vbo->stride_vertexcolor, BUFFER_OFFSET(vbo->ofs_vertexcolor)); - glState.vertexAttribPointersSet |= ATTR_COLOR; - } - - if((attribBits & ATTR_LIGHTDIRECTION) && !(glState.vertexAttribPointersSet & ATTR_LIGHTDIRECTION)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_LIGHTDIRECTION )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_LIGHTDIRECTION, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_lightdir, BUFFER_OFFSET(vbo->ofs_lightdir)); - glState.vertexAttribPointersSet |= ATTR_LIGHTDIRECTION; - } - - if((attribBits & ATTR_POSITION2) && (!(glState.vertexAttribPointersSet & ATTR_POSITION2) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_POSITION2 )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_POSITION2, 3, GL_FLOAT, 0, vbo->stride_xyz, BUFFER_OFFSET(vbo->ofs_xyz + oldFrame * vbo->size_xyz)); - glState.vertexAttribPointersSet |= ATTR_POSITION2; - } - - if((attribBits & ATTR_NORMAL2) && (!(glState.vertexAttribPointersSet & ATTR_NORMAL2) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_NORMAL2 )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_NORMAL2, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_normal, BUFFER_OFFSET(vbo->ofs_normal + oldFrame * vbo->size_normal)); - glState.vertexAttribPointersSet |= ATTR_NORMAL2; - } - -#ifdef USE_VERT_TANGENT_SPACE - if((attribBits & ATTR_TANGENT2) && (!(glState.vertexAttribPointersSet & ATTR_TANGENT2) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TANGENT2 )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TANGENT2, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_tangent, BUFFER_OFFSET(vbo->ofs_tangent + oldFrame * vbo->size_normal)); // FIXME - glState.vertexAttribPointersSet |= ATTR_TANGENT2; - } -#endif - -} - - -shaderProgram_t *GLSL_GetGenericShaderProgram(int stage) -{ - shaderStage_t *pStage = tess.xstages[stage]; - int shaderAttribs = 0; - - if (tess.fogNum && pStage->adjustColorsForFog) - { - shaderAttribs |= GENERICDEF_USE_FOG; - } - - if (pStage->bundle[1].image[0] && tess.shader->multitextureEnv) - { - shaderAttribs |= GENERICDEF_USE_LIGHTMAP; - } - - switch (pStage->rgbGen) - { - case CGEN_LIGHTING_DIFFUSE: - shaderAttribs |= GENERICDEF_USE_RGBAGEN; - break; - default: - break; - } - - switch (pStage->alphaGen) - { - case AGEN_LIGHTING_SPECULAR: - case AGEN_PORTAL: - shaderAttribs |= GENERICDEF_USE_RGBAGEN; - break; - default: - break; - } - - if (pStage->bundle[0].tcGen != TCGEN_TEXTURE) - { - shaderAttribs |= GENERICDEF_USE_TCGEN_AND_TCMOD; - } - - if (tess.shader->numDeforms && !ShaderRequiresCPUDeforms(tess.shader)) - { - shaderAttribs |= GENERICDEF_USE_DEFORM_VERTEXES; - } - - if (glState.vertexAnimation) - { - shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION; - } - - if (pStage->bundle[0].numTexMods) - { - shaderAttribs |= GENERICDEF_USE_TCGEN_AND_TCMOD; - } - - return &tr.genericShader[shaderAttribs]; -} diff --git a/code/renderergl2/tr_image.c b/code/renderergl2/tr_image.c deleted file mode 100644 index 243d27dff3..0000000000 --- a/code/renderergl2/tr_image.c +++ /dev/null @@ -1,3437 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_image.c -#include "tr_local.h" - -static byte s_intensitytable[256]; -static unsigned char s_gammatable[256]; - -int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; -int gl_filter_max = GL_LINEAR; - -#define FILE_HASH_SIZE 1024 -static image_t* hashTable[FILE_HASH_SIZE]; - -/* -** R_GammaCorrect -*/ -void R_GammaCorrect( byte *buffer, int bufSize ) { - int i; - - for ( i = 0; i < bufSize; i++ ) { - buffer[i] = s_gammatable[buffer[i]]; - } -} - -typedef struct { - char *name; - int minimize, maximize; -} textureMode_t; - -textureMode_t modes[] = { - {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, - {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, - {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, - {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, - {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, - {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} -}; - -/* -================ -return a hash value for the filename -================ -*/ -static long generateHashValue( const char *fname ) { - int i; - long hash; - char letter; - - hash = 0; - i = 0; - while (fname[i] != '\0') { - letter = tolower(fname[i]); - if (letter =='.') break; // don't include extension - if (letter =='\\') letter = '/'; // damn path names - hash+=(long)(letter)*(i+119); - i++; - } - hash &= (FILE_HASH_SIZE-1); - return hash; -} - -/* -=============== -GL_TextureMode -=============== -*/ -void GL_TextureMode( const char *string ) { - int i; - image_t *glt; - - for ( i=0 ; i< 6 ; i++ ) { - if ( !Q_stricmp( modes[i].name, string ) ) { - break; - } - } - - // hack to prevent trilinear from being set on voodoo, - // because their driver freaks... - if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) { - ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" ); - i = 3; - } - - - if ( i == 6 ) { - ri.Printf (PRINT_ALL, "bad filter name\n"); - return; - } - - gl_filter_min = modes[i].minimize; - gl_filter_max = modes[i].maximize; - - // change all the existing mipmap texture objects - for ( i = 0 ; i < tr.numImages ; i++ ) { - glt = tr.images[ i ]; - if ( glt->flags & IMGFLAG_MIPMAP ) { - GL_Bind (glt); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - } -} - -/* -=============== -R_SumOfUsedImages -=============== -*/ -int R_SumOfUsedImages( void ) { - int total; - int i; - - total = 0; - for ( i = 0; i < tr.numImages; i++ ) { - if ( tr.images[i]->frameUsed == tr.frameCount ) { - total += tr.images[i]->uploadWidth * tr.images[i]->uploadHeight; - } - } - - return total; -} - -/* -=============== -R_ImageList_f -=============== -*/ -void R_ImageList_f( void ) { - int i; - int estTotalSize = 0; - - ri.Printf(PRINT_ALL, "\n -w-- -h-- type -size- --name-------\n"); - - for ( i = 0 ; i < tr.numImages ; i++ ) - { - image_t *image = tr.images[i]; - char *format = "???? "; - char *sizeSuffix; - int estSize; - int displaySize; - - estSize = image->uploadHeight * image->uploadWidth; - - switch(image->internalFormat) - { - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: - format = "sDXT1"; - // 64 bits per 16 pixels, so 4 bits per pixel - estSize /= 2; - break; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - format = "sDXT5"; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB: - format = "sBPTC"; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: - format = "LATC "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - format = "DXT1 "; - // 64 bits per 16 pixels, so 4 bits per pixel - estSize /= 2; - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - format = "DXT5 "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: - format = "BPTC "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_RGB4_S3TC: - format = "S3TC "; - // same as DXT1? - estSize /= 2; - break; - case GL_RGBA4: - case GL_RGBA8: - case GL_RGBA: - format = "RGBA "; - // 4 bytes per pixel - estSize *= 4; - break; - case GL_LUMINANCE8: - case GL_LUMINANCE16: - case GL_LUMINANCE: - format = "L "; - // 1 byte per pixel? - break; - case GL_RGB5: - case GL_RGB8: - case GL_RGB: - format = "RGB "; - // 3 bytes per pixel? - estSize *= 3; - break; - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE16_ALPHA16: - case GL_LUMINANCE_ALPHA: - format = "LA "; - // 2 bytes per pixel? - estSize *= 2; - break; - case GL_SRGB_EXT: - case GL_SRGB8_EXT: - format = "sRGB "; - // 3 bytes per pixel? - estSize *= 3; - break; - case GL_SRGB_ALPHA_EXT: - case GL_SRGB8_ALPHA8_EXT: - format = "sRGBA"; - // 4 bytes per pixel? - estSize *= 4; - break; - case GL_SLUMINANCE_EXT: - case GL_SLUMINANCE8_EXT: - format = "sL "; - // 1 byte per pixel? - break; - case GL_SLUMINANCE_ALPHA_EXT: - case GL_SLUMINANCE8_ALPHA8_EXT: - format = "sLA "; - // 2 byte per pixel? - estSize *= 2; - break; - } - - // mipmap adds about 50% - if (image->flags & IMGFLAG_MIPMAP) - estSize += estSize / 2; - - sizeSuffix = "b "; - displaySize = estSize; - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "kb"; - } - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "Mb"; - } - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "Gb"; - } - - ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName); - estTotalSize += estSize; - } - - ri.Printf (PRINT_ALL, " ---------\n"); - ri.Printf (PRINT_ALL, " approx %i bytes\n", estTotalSize); - ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages ); -} - -//======================================================================= - -/* -================ -ResampleTexture - -Used to resample images in a more general than quartering fashion. - -This will only be filtered properly if the resampled size -is greater than half the original size. - -If a larger shrinking is needed, use the mipmap function -before or after. -================ -*/ -static void ResampleTexture( byte *in, int inwidth, int inheight, byte *out, - int outwidth, int outheight ) { - int i, j; - byte *inrow, *inrow2; - int frac, fracstep; - int p1[2048], p2[2048]; - byte *pix1, *pix2, *pix3, *pix4; - - if (outwidth>2048) - ri.Error(ERR_DROP, "ResampleTexture: max width"); - - fracstep = inwidth*0x10000/outwidth; - - frac = fracstep>>2; - for ( i=0 ; i>16); - frac += fracstep; - } - frac = 3*(fracstep>>2); - for ( i=0 ; i>16); - frac += fracstep; - } - - for (i=0 ; i>2; - *out++ = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; - *out++ = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; - *out++ = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; - } - } -} - -static void RGBAtoYCoCgA(const byte *in, byte *out, int width, int height) -{ - int x, y; - - for (y = 0; y < height; y++) - { - const byte *inbyte = in + y * width * 4; - byte *outbyte = out + y * width * 4; - - for (x = 0; x < width; x++) - { - byte r, g, b, a, rb2; - - r = *inbyte++; - g = *inbyte++; - b = *inbyte++; - a = *inbyte++; - rb2 = (r + b) >> 1; - - *outbyte++ = (g + rb2) >> 1; // Y = R/4 + G/2 + B/4 - *outbyte++ = (r - b + 256) >> 1; // Co = R/2 - B/2 - *outbyte++ = (g - rb2 + 256) >> 1; // Cg = -R/4 + G/2 - B/4 - *outbyte++ = a; - } - } -} - -static void YCoCgAtoRGBA(const byte *in, byte *out, int width, int height) -{ - int x, y; - - for (y = 0; y < height; y++) - { - const byte *inbyte = in + y * width * 4; - byte *outbyte = out + y * width * 4; - - for (x = 0; x < width; x++) - { - byte _Y, Co, Cg, a; - - _Y = *inbyte++; - Co = *inbyte++; - Cg = *inbyte++; - a = *inbyte++; - - *outbyte++ = CLAMP(_Y + Co - Cg, 0, 255); // R = Y + Co - Cg - *outbyte++ = CLAMP(_Y + Cg - 128, 0, 255); // G = Y + Cg - *outbyte++ = CLAMP(_Y - Co - Cg + 256, 0, 255); // B = Y - Co - Cg - *outbyte++ = a; - } - } -} - - -// uses a sobel filter to change a texture to a normal map -static void RGBAtoNormal(const byte *in, byte *out, int width, int height, qboolean clampToEdge) -{ - int x, y, max; - - // convert to heightmap, storing in alpha - // same as converting to Y in YCoCg - max = 1; - for (y = 0; y < height; y++) - { - const byte *inbyte = in + y * width * 4; - byte *outbyte = out + y * width * 4 + 3; - - for (x = 0; x < width; x++) - { - byte result = (inbyte[0] >> 2) + (inbyte[1] >> 1) + (inbyte[2] >> 2); - result = result * result / 255; // Make linear - *outbyte = result; - max = MAX(max, *outbyte); - outbyte += 4; - inbyte += 4; - } - } - - // level out heights - if (max < 255) - { - for (y = 0; y < height; y++) - { - byte *outbyte = out + y * width * 4 + 3; - - for (x = 0; x < width; x++) - { - *outbyte = *outbyte + (255 - max); - outbyte += 4; - } - } - } - - - // now run sobel filter over height values to generate X and Y - // then normalize - for (y = 0; y < height; y++) - { - byte *outbyte = out + y * width * 4; - - for (x = 0; x < width; x++) - { - // 0 1 2 - // 3 4 5 - // 6 7 8 - - byte s[9]; - int x2, y2, i; - vec3_t normal; - - i = 0; - for (y2 = -1; y2 <= 1; y2++) - { - int src_y = y + y2; - - if (clampToEdge) - { - src_y = CLAMP(src_y, 0, height - 1); - } - else - { - src_y = (src_y + height) % height; - } - - - for (x2 = -1; x2 <= 1; x2++) - { - int src_x = x + x2; - - if (clampToEdge) - { - src_x = CLAMP(src_x, 0, height - 1); - } - else - { - src_x = (src_x + height) % height; - } - - s[i++] = *(out + (src_y * width + src_x) * 4 + 3); - } - } - - normal[0] = s[0] - s[2] - + 2 * s[3] - 2 * s[5] - + s[6] - s[8]; - - normal[1] = s[0] + 2 * s[1] + s[2] - - - s[6] - 2 * s[7] - s[8]; - - normal[2] = s[4] * 4; - - if (!VectorNormalize2(normal, normal)) - { - VectorSet(normal, 0, 0, 1); - } - - *outbyte++ = FloatToOffsetByte(normal[0]); - *outbyte++ = FloatToOffsetByte(normal[1]); - *outbyte++ = FloatToOffsetByte(normal[2]); - outbyte++; - } - } -} - -#define COPYSAMPLE(a,b) *(unsigned int *)(a) = *(unsigned int *)(b) - -// based on Fast Curve Based Interpolation -// from Fast Artifacts-Free Image Interpolation (http://www.andreagiachetti.it/icbi/) -// assumes data has a 2 pixel thick border of clamped or wrapped data -// expects data to be a grid with even (0, 0), (2, 0), (0, 2), (2, 2) etc pixels filled -// only performs FCBI on specified component -static void DoFCBI(byte *in, byte *out, int width, int height, int component) -{ - int x, y; - byte *outbyte, *inbyte; - - // copy in to out - for (y = 2; y < height - 2; y += 2) - { - inbyte = in + (y * width + 2) * 4 + component; - outbyte = out + (y * width + 2) * 4 + component; - - for (x = 2; x < width - 2; x += 2) - { - *outbyte = *inbyte; - outbyte += 8; - inbyte += 8; - } - } - - for (y = 3; y < height - 3; y += 2) - { - // diagonals - // - // NWp - northwest interpolated pixel - // NEp - northeast interpolated pixel - // NWd - northwest first derivative - // NEd - northeast first derivative - // NWdd - northwest second derivative - // NEdd - northeast second derivative - // - // Uses these samples: - // - // 0 - // - - a - b - - - // - - - - - - - - // c - d - e - f - // 0 - - - - - - - - // g - h - i - j - // - - - - - - - - // - - k - l - - - // - // x+2 uses these samples: - // - // 0 - // - - - - a - b - - - // - - - - - - - - - - // - - c - d - e - f - // 0 - - - - - - - - - - // - - g - h - i - j - // - - - - - - - - - - // - - - - k - l - - - // - // so we can reuse 8 of them on next iteration - // - // a=b, c=d, d=e, e=f, g=h, h=i, i=j, k=l - // - // only b, f, j, and l need to be sampled on next iteration - - byte sa, sb, sc, sd, se, sf, sg, sh, si, sj, sk, sl; - byte *line1, *line2, *line3, *line4; - - x = 3; - - // optimization one - // SAMPLE2(sa, x-1, y-3); - //SAMPLE2(sc, x-3, y-1); SAMPLE2(sd, x-1, y-1); SAMPLE2(se, x+1, y-1); - //SAMPLE2(sg, x-3, y+1); SAMPLE2(sh, x-1, y+1); SAMPLE2(si, x+1, y+1); - // SAMPLE2(sk, x-1, y+3); - - // optimization two - line1 = in + ((y - 3) * width + (x - 1)) * 4 + component; - line2 = in + ((y - 1) * width + (x - 3)) * 4 + component; - line3 = in + ((y + 1) * width + (x - 3)) * 4 + component; - line4 = in + ((y + 3) * width + (x - 1)) * 4 + component; - - // COPYSAMPLE(sa, line1); line1 += 8; - //COPYSAMPLE(sc, line2); line2 += 8; COPYSAMPLE(sd, line2); line2 += 8; COPYSAMPLE(se, line2); line2 += 8; - //COPYSAMPLE(sg, line3); line3 += 8; COPYSAMPLE(sh, line3); line3 += 8; COPYSAMPLE(si, line3); line3 += 8; - // COPYSAMPLE(sk, line4); line4 += 8; - - sa = *line1; line1 += 8; - sc = *line2; line2 += 8; sd = *line2; line2 += 8; se = *line2; line2 += 8; - sg = *line3; line3 += 8; sh = *line3; line3 += 8; si = *line3; line3 += 8; - sk = *line4; line4 += 8; - - outbyte = out + (y * width + x) * 4 + component; - - for ( ; x < width - 3; x += 2) - { - int NWd, NEd, NWp, NEp; - - // original - // SAMPLE2(sa, x-1, y-3); SAMPLE2(sb, x+1, y-3); - //SAMPLE2(sc, x-3, y-1); SAMPLE2(sd, x-1, y-1); SAMPLE2(se, x+1, y-1); SAMPLE2(sf, x+3, y-1); - //SAMPLE2(sg, x-3, y+1); SAMPLE2(sh, x-1, y+1); SAMPLE2(si, x+1, y+1); SAMPLE2(sj, x+3, y+1); - // SAMPLE2(sk, x-1, y+3); SAMPLE2(sl, x+1, y+3); - - // optimization one - //SAMPLE2(sb, x+1, y-3); - //SAMPLE2(sf, x+3, y-1); - //SAMPLE2(sj, x+3, y+1); - //SAMPLE2(sl, x+1, y+3); - - // optimization two - //COPYSAMPLE(sb, line1); line1 += 8; - //COPYSAMPLE(sf, line2); line2 += 8; - //COPYSAMPLE(sj, line3); line3 += 8; - //COPYSAMPLE(sl, line4); line4 += 8; - - sb = *line1; line1 += 8; - sf = *line2; line2 += 8; - sj = *line3; line3 += 8; - sl = *line4; line4 += 8; - - NWp = sd + si; - NEp = se + sh; - NWd = abs(sd - si); - NEd = abs(se - sh); - - if (NWd > 100 || NEd > 100 || abs(NWp-NEp) > 200) - { - if (NWd < NEd) - *outbyte = NWp >> 1; - else - *outbyte = NEp >> 1; - } - else - { - int NWdd, NEdd; - - //NEdd = abs(sg + sd + sb - 3 * (se + sh) + sk + si + sf); - //NWdd = abs(sa + se + sj - 3 * (sd + si) + sc + sh + sl); - NEdd = abs(sg + sb - 3 * NEp + sk + sf + NWp); - NWdd = abs(sa + sj - 3 * NWp + sc + sl + NEp); - - if (NWdd > NEdd) - *outbyte = NWp >> 1; - else - *outbyte = NEp >> 1; - } - - outbyte += 8; - - // COPYSAMPLE(sa, sb); - //COPYSAMPLE(sc, sd); COPYSAMPLE(sd, se); COPYSAMPLE(se, sf); - //COPYSAMPLE(sg, sh); COPYSAMPLE(sh, si); COPYSAMPLE(si, sj); - // COPYSAMPLE(sk, sl); - - sa = sb; - sc = sd; sd = se; se = sf; - sg = sh; sh = si; si = sj; - sk = sl; - } - } - - // hack: copy out to in again - for (y = 3; y < height - 3; y += 2) - { - inbyte = out + (y * width + 3) * 4 + component; - outbyte = in + (y * width + 3) * 4 + component; - - for (x = 3; x < width - 3; x += 2) - { - *outbyte = *inbyte; - outbyte += 8; - inbyte += 8; - } - } - - for (y = 2; y < height - 3; y++) - { - // horizontal & vertical - // - // hp - horizontally interpolated pixel - // vp - vertically interpolated pixel - // hd - horizontal first derivative - // vd - vertical first derivative - // hdd - horizontal second derivative - // vdd - vertical second derivative - // Uses these samples: - // - // 0 - // - a - b - - // c - d - e - // 0 - f - g - - // h - i - j - // - k - l - - // - // x+2 uses these samples: - // - // 0 - // - - - a - b - - // - - c - d - e - // 0 - - - f - g - - // - - h - i - j - // - - - k - l - - // - // so we can reuse 7 of them on next iteration - // - // a=b, c=d, d=e, f=g, h=i, i=j, k=l - // - // only b, e, g, j, and l need to be sampled on next iteration - - byte sa, sb, sc, sd, se, sf, sg, sh, si, sj, sk, sl; - byte *line1, *line2, *line3, *line4, *line5; - - //x = (y + 1) % 2; - x = (y + 1) % 2 + 2; - - // optimization one - // SAMPLE2(sa, x-1, y-2); - //SAMPLE2(sc, x-2, y-1); SAMPLE2(sd, x, y-1); - // SAMPLE2(sf, x-1, y ); - //SAMPLE2(sh, x-2, y+1); SAMPLE2(si, x, y+1); - // SAMPLE2(sk, x-1, y+2); - - line1 = in + ((y - 2) * width + (x - 1)) * 4 + component; - line2 = in + ((y - 1) * width + (x - 2)) * 4 + component; - line3 = in + ((y ) * width + (x - 1)) * 4 + component; - line4 = in + ((y + 1) * width + (x - 2)) * 4 + component; - line5 = in + ((y + 2) * width + (x - 1)) * 4 + component; - - // COPYSAMPLE(sa, line1); line1 += 8; - //COPYSAMPLE(sc, line2); line2 += 8; COPYSAMPLE(sd, line2); line2 += 8; - // COPYSAMPLE(sf, line3); line3 += 8; - //COPYSAMPLE(sh, line4); line4 += 8; COPYSAMPLE(si, line4); line4 += 8; - // COPYSAMPLE(sk, line5); line5 += 8; - - sa = *line1; line1 += 8; - sc = *line2; line2 += 8; sd = *line2; line2 += 8; - sf = *line3; line3 += 8; - sh = *line4; line4 += 8; si = *line4; line4 += 8; - sk = *line5; line5 += 8; - - outbyte = out + (y * width + x) * 4 + component; - - for ( ; x < width - 3; x+=2) - { - int hd, vd, hp, vp; - - // SAMPLE2(sa, x-1, y-2); SAMPLE2(sb, x+1, y-2); - //SAMPLE2(sc, x-2, y-1); SAMPLE2(sd, x, y-1); SAMPLE2(se, x+2, y-1); - // SAMPLE2(sf, x-1, y ); SAMPLE2(sg, x+1, y ); - //SAMPLE2(sh, x-2, y+1); SAMPLE2(si, x, y+1); SAMPLE2(sj, x+2, y+1); - // SAMPLE2(sk, x-1, y+2); SAMPLE2(sl, x+1, y+2); - - // optimization one - //SAMPLE2(sb, x+1, y-2); - //SAMPLE2(se, x+2, y-1); - //SAMPLE2(sg, x+1, y ); - //SAMPLE2(sj, x+2, y+1); - //SAMPLE2(sl, x+1, y+2); - - //COPYSAMPLE(sb, line1); line1 += 8; - //COPYSAMPLE(se, line2); line2 += 8; - //COPYSAMPLE(sg, line3); line3 += 8; - //COPYSAMPLE(sj, line4); line4 += 8; - //COPYSAMPLE(sl, line5); line5 += 8; - - sb = *line1; line1 += 8; - se = *line2; line2 += 8; - sg = *line3; line3 += 8; - sj = *line4; line4 += 8; - sl = *line5; line5 += 8; - - hp = sf + sg; - vp = sd + si; - hd = abs(sf - sg); - vd = abs(sd - si); - - if (hd > 100 || vd > 100 || abs(hp-vp) > 200) - { - if (hd < vd) - *outbyte = hp >> 1; - else - *outbyte = vp >> 1; - } - else - { - int hdd, vdd; - - //hdd = abs(sc[i] + sd[i] + se[i] - 3 * (sf[i] + sg[i]) + sh[i] + si[i] + sj[i]); - //vdd = abs(sa[i] + sf[i] + sk[i] - 3 * (sd[i] + si[i]) + sb[i] + sg[i] + sl[i]); - - hdd = abs(sc + se - 3 * hp + sh + sj + vp); - vdd = abs(sa + sk - 3 * vp + sb + sl + hp); - - if (hdd > vdd) - *outbyte = hp >> 1; - else - *outbyte = vp >> 1; - } - - outbyte += 8; - - // COPYSAMPLE(sa, sb); - //COPYSAMPLE(sc, sd); COPYSAMPLE(sd, se); - // COPYSAMPLE(sf, sg); - //COPYSAMPLE(sh, si); COPYSAMPLE(si, sj); - // COPYSAMPLE(sk, sl); - sa = sb; - sc = sd; sd = se; - sf = sg; - sh = si; si = sj; - sk = sl; - } - } -} - -// Similar to FCBI, but throws out the second order derivatives for speed -static void DoFCBIQuick(byte *in, byte *out, int width, int height, int component) -{ - int x, y; - byte *outbyte, *inbyte; - - // copy in to out - for (y = 2; y < height - 2; y += 2) - { - inbyte = in + (y * width + 2) * 4 + component; - outbyte = out + (y * width + 2) * 4 + component; - - for (x = 2; x < width - 2; x += 2) - { - *outbyte = *inbyte; - outbyte += 8; - inbyte += 8; - } - } - - for (y = 3; y < height - 4; y += 2) - { - byte sd, se, sh, si; - byte *line2, *line3; - - x = 3; - - line2 = in + ((y - 1) * width + (x - 1)) * 4 + component; - line3 = in + ((y + 1) * width + (x - 1)) * 4 + component; - - sd = *line2; line2 += 8; - sh = *line3; line3 += 8; - - outbyte = out + (y * width + x) * 4 + component; - - for ( ; x < width - 4; x += 2) - { - int NWd, NEd, NWp, NEp; - - se = *line2; line2 += 8; - si = *line3; line3 += 8; - - NWp = sd + si; - NEp = se + sh; - NWd = abs(sd - si); - NEd = abs(se - sh); - - if (NWd < NEd) - *outbyte = NWp >> 1; - else - *outbyte = NEp >> 1; - - outbyte += 8; - - sd = se; - sh = si; - } - } - - // hack: copy out to in again - for (y = 3; y < height - 3; y += 2) - { - inbyte = out + (y * width + 3) * 4 + component; - outbyte = in + (y * width + 3) * 4 + component; - - for (x = 3; x < width - 3; x += 2) - { - *outbyte = *inbyte; - outbyte += 8; - inbyte += 8; - } - } - - for (y = 2; y < height - 3; y++) - { - byte sd, sf, sg, si; - byte *line2, *line3, *line4; - - x = (y + 1) % 2 + 2; - - line2 = in + ((y - 1) * width + (x )) * 4 + component; - line3 = in + ((y ) * width + (x - 1)) * 4 + component; - line4 = in + ((y + 1) * width + (x )) * 4 + component; - - outbyte = out + (y * width + x) * 4 + component; - - sf = *line3; line3 += 8; - - for ( ; x < width - 3; x+=2) - { - int hd, vd, hp, vp; - - sd = *line2; line2 += 8; - sg = *line3; line3 += 8; - si = *line4; line4 += 8; - - hp = sf + sg; - vp = sd + si; - hd = abs(sf - sg); - vd = abs(sd - si); - - if (hd < vd) - *outbyte = hp >> 1; - else - *outbyte = vp >> 1; - - outbyte += 8; - - sf = sg; - } - } -} - -// Similar to DoFCBIQuick, but just takes the average instead of checking derivatives -// as well, this operates on all four components -static void DoLinear(byte *in, byte *out, int width, int height) -{ - int x, y, i; - byte *outbyte, *inbyte; - - // copy in to out - for (y = 2; y < height - 2; y += 2) - { - x = 2; - - inbyte = in + (y * width + x) * 4; - outbyte = out + (y * width + x) * 4; - - for ( ; x < width - 2; x += 2) - { - COPYSAMPLE(outbyte, inbyte); - outbyte += 8; - inbyte += 8; - } - } - - for (y = 1; y < height - 1; y += 2) - { - byte sd[4] = {0}, se[4] = {0}, sh[4] = {0}, si[4] = {0}; - byte *line2, *line3; - - x = 1; - - line2 = in + ((y - 1) * width + (x - 1)) * 4; - line3 = in + ((y + 1) * width + (x - 1)) * 4; - - COPYSAMPLE(sd, line2); line2 += 8; - COPYSAMPLE(sh, line3); line3 += 8; - - outbyte = out + (y * width + x) * 4; - - for ( ; x < width - 1; x += 2) - { - COPYSAMPLE(se, line2); line2 += 8; - COPYSAMPLE(si, line3); line3 += 8; - - for (i = 0; i < 4; i++) - { - *outbyte++ = (sd[i] + si[i] + se[i] + sh[i]) >> 2; - } - - outbyte += 4; - - COPYSAMPLE(sd, se); - COPYSAMPLE(sh, si); - } - } - - // hack: copy out to in again - for (y = 1; y < height - 1; y += 2) - { - x = 1; - - inbyte = out + (y * width + x) * 4; - outbyte = in + (y * width + x) * 4; - - for ( ; x < width - 1; x += 2) - { - COPYSAMPLE(outbyte, inbyte); - outbyte += 8; - inbyte += 8; - } - } - - for (y = 1; y < height - 1; y++) - { - byte sd[4], sf[4], sg[4], si[4]; - byte *line2, *line3, *line4; - - x = y % 2 + 1; - - line2 = in + ((y - 1) * width + (x )) * 4; - line3 = in + ((y ) * width + (x - 1)) * 4; - line4 = in + ((y + 1) * width + (x )) * 4; - - COPYSAMPLE(sf, line3); line3 += 8; - - outbyte = out + (y * width + x) * 4; - - for ( ; x < width - 1; x += 2) - { - COPYSAMPLE(sd, line2); line2 += 8; - COPYSAMPLE(sg, line3); line3 += 8; - COPYSAMPLE(si, line4); line4 += 8; - - for (i = 0; i < 4; i++) - { - *outbyte++ = (sf[i] + sg[i] + sd[i] + si[i]) >> 2; - } - - outbyte += 4; - - COPYSAMPLE(sf, sg); - } - } -} - - -static void ExpandHalfTextureToGrid( byte *data, int width, int height) -{ - int x, y; - - for (y = height / 2; y > 0; y--) - { - byte *outbyte = data + ((y * 2 - 1) * (width) - 2) * 4; - byte *inbyte = data + (y * (width / 2) - 1) * 4; - - for (x = width / 2; x > 0; x--) - { - COPYSAMPLE(outbyte, inbyte); - - outbyte -= 8; - inbyte -= 4; - } - } -} - -static void FillInNormalizedZ(const byte *in, byte *out, int width, int height) -{ - int x, y; - - for (y = 0; y < height; y++) - { - const byte *inbyte = in + y * width * 4; - byte *outbyte = out + y * width * 4; - - for (x = 0; x < width; x++) - { - byte nx, ny, nz, h; - float fnx, fny, fll, fnz; - - nx = *inbyte++; - ny = *inbyte++; - inbyte++; - h = *inbyte++; - - fnx = OffsetByteToFloat(nx); - fny = OffsetByteToFloat(ny); - fll = 1.0f - fnx * fnx - fny * fny; - if (fll >= 0.0f) - fnz = (float)sqrt(fll); - else - fnz = 0.0f; - - nz = FloatToOffsetByte(fnz); - - *outbyte++ = nx; - *outbyte++ = ny; - *outbyte++ = nz; - *outbyte++ = h; - } - } -} - - -// size must be even -#define WORKBLOCK_SIZE 128 -#define WORKBLOCK_BORDER 4 -#define WORKBLOCK_REALSIZE (WORKBLOCK_SIZE + WORKBLOCK_BORDER * 2) - -// assumes that data has already been expanded into a 2x2 grid -static void FCBIByBlock(byte *data, int width, int height, qboolean clampToEdge, qboolean normalized) -{ - byte workdata[WORKBLOCK_REALSIZE * WORKBLOCK_REALSIZE * 4]; - byte outdata[WORKBLOCK_REALSIZE * WORKBLOCK_REALSIZE * 4]; - byte *inbyte, *outbyte; - int x, y; - int srcx, srcy; - - ExpandHalfTextureToGrid(data, width, height); - - for (y = 0; y < height; y += WORKBLOCK_SIZE) - { - for (x = 0; x < width; x += WORKBLOCK_SIZE) - { - int x2, y2; - int workwidth, workheight, fullworkwidth, fullworkheight; - - workwidth = MIN(WORKBLOCK_SIZE, width - x); - workheight = MIN(WORKBLOCK_SIZE, height - y); - - fullworkwidth = workwidth + WORKBLOCK_BORDER * 2; - fullworkheight = workheight + WORKBLOCK_BORDER * 2; - - //memset(workdata, 0, WORKBLOCK_REALSIZE * WORKBLOCK_REALSIZE * 4); - - // fill in work block - for (y2 = 0; y2 < fullworkheight; y2 += 2) - { - srcy = y + y2 - WORKBLOCK_BORDER; - - if (clampToEdge) - { - srcy = CLAMP(srcy, 0, height - 2); - } - else - { - srcy = (srcy + height) % height; - } - - outbyte = workdata + y2 * fullworkwidth * 4; - inbyte = data + srcy * width * 4; - - for (x2 = 0; x2 < fullworkwidth; x2 += 2) - { - srcx = x + x2 - WORKBLOCK_BORDER; - - if (clampToEdge) - { - srcx = CLAMP(srcx, 0, width - 2); - } - else - { - srcx = (srcx + width) % width; - } - - COPYSAMPLE(outbyte, inbyte + srcx * 4); - outbyte += 8; - } - } - - // submit work block - DoLinear(workdata, outdata, fullworkwidth, fullworkheight); - - if (!normalized) - { - switch (r_imageUpsampleType->integer) - { - case 0: - break; - case 1: - DoFCBIQuick(workdata, outdata, fullworkwidth, fullworkheight, 0); - break; - case 2: - default: - DoFCBI(workdata, outdata, fullworkwidth, fullworkheight, 0); - break; - } - } - else - { - switch (r_imageUpsampleType->integer) - { - case 0: - break; - case 1: - DoFCBIQuick(workdata, outdata, fullworkwidth, fullworkheight, 0); - DoFCBIQuick(workdata, outdata, fullworkwidth, fullworkheight, 1); - break; - case 2: - default: - DoFCBI(workdata, outdata, fullworkwidth, fullworkheight, 0); - DoFCBI(workdata, outdata, fullworkwidth, fullworkheight, 1); - break; - } - } - - // copy back work block - for (y2 = 0; y2 < workheight; y2++) - { - inbyte = outdata + ((y2 + WORKBLOCK_BORDER) * fullworkwidth + WORKBLOCK_BORDER) * 4; - outbyte = data + ((y + y2) * width + x) * 4; - for (x2 = 0; x2 < workwidth; x2++) - { - COPYSAMPLE(outbyte, inbyte); - outbyte += 4; - inbyte += 4; - } - } - } - } -} -#undef COPYSAMPLE - -/* -================ -R_LightScaleTexture - -Scale up the pixel values in a texture to increase the -lighting range -================ -*/ -void R_LightScaleTexture (byte *in, int inwidth, int inheight, qboolean only_gamma ) -{ - if ( only_gamma ) - { - if ( !glConfig.deviceSupportsGamma ) - { - int i, c; - byte *p; - - p = in; - - c = inwidth*inheight; - for (i=0 ; i> 1; - outHeight = inHeight >> 1; - temp = ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 ); - - inWidthMask = inWidth - 1; - inHeightMask = inHeight - 1; - - for ( i = 0 ; i < outHeight ; i++ ) { - for ( j = 0 ; j < outWidth ; j++ ) { - outpix = (byte *) ( temp + i * outWidth + j ); - for ( k = 0 ; k < 4 ; k++ ) { - total = - 1 * (&in[ 4*(((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2-1)&inHeightMask)*inWidth + ((j*2 )&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask)) ])[k] + - 1 * (&in[ 4*(((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask)) ])[k] + - - 2 * (&in[ 4*(((i*2 )&inHeightMask)*inWidth + ((j*2-1)&inWidthMask)) ])[k] + - 4 * (&in[ 4*(((i*2 )&inHeightMask)*inWidth + ((j*2 )&inWidthMask)) ])[k] + - 4 * (&in[ 4*(((i*2 )&inHeightMask)*inWidth + ((j*2+1)&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2 )&inHeightMask)*inWidth + ((j*2+2)&inWidthMask)) ])[k] + - - 2 * (&in[ 4*(((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask)) ])[k] + - 4 * (&in[ 4*(((i*2+1)&inHeightMask)*inWidth + ((j*2 )&inWidthMask)) ])[k] + - 4 * (&in[ 4*(((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask)) ])[k] + - - 1 * (&in[ 4*(((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2+2)&inHeightMask)*inWidth + ((j*2 )&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask)) ])[k] + - 1 * (&in[ 4*(((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask)) ])[k]; - outpix[k] = total / 36; - } - } - } - - Com_Memcpy( in, temp, outWidth * outHeight * 4 ); - ri.Hunk_FreeTempMemory( temp ); -} - - -static void R_MipMapsRGB( byte *in, int inWidth, int inHeight) -{ - int i, j, k; - int outWidth, outHeight; - byte *temp; - - outWidth = inWidth >> 1; - outHeight = inHeight >> 1; - temp = ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 ); - - for ( i = 0 ; i < outHeight ; i++ ) { - byte *outbyte = temp + ( i * outWidth ) * 4; - byte *inbyte1 = in + ( i * 2 * inWidth ) * 4; - byte *inbyte2 = in + ( (i * 2 + 1) * inWidth ) * 4; - for ( j = 0 ; j < outWidth ; j++ ) { - for ( k = 0 ; k < 3 ; k++ ) { - float total, current; - - current = ByteToFloat(inbyte1[0]); total = sRGBtoRGB(current); - current = ByteToFloat(inbyte1[4]); total += sRGBtoRGB(current); - current = ByteToFloat(inbyte2[0]); total += sRGBtoRGB(current); - current = ByteToFloat(inbyte2[4]); total += sRGBtoRGB(current); - - total *= 0.25f; - - inbyte1++; - inbyte2++; - - current = RGBtosRGB(total); - *outbyte++ = FloatToByte(current); - } - *outbyte++ = (inbyte1[0] + inbyte1[4] + inbyte2[0] + inbyte2[4]) >> 2; - inbyte1 += 5; - inbyte2 += 5; - } - } - - Com_Memcpy( in, temp, outWidth * outHeight * 4 ); - ri.Hunk_FreeTempMemory( temp ); -} - -/* -================ -R_MipMap - -Operates in place, quartering the size of the texture -================ -*/ -static void R_MipMap (byte *in, int width, int height) { - int i, j; - byte *out; - int row; - - if ( !r_simpleMipMaps->integer ) { - R_MipMap2( in, width, height ); - return; - } - - if ( width == 1 && height == 1 ) { - return; - } - - row = width * 4; - out = in; - width >>= 1; - height >>= 1; - - if ( width == 0 || height == 0 ) { - width += height; // get largest - for (i=0 ; i>1; - out[1] = ( in[1] + in[5] )>>1; - out[2] = ( in[2] + in[6] )>>1; - out[3] = ( in[3] + in[7] )>>1; - } - return; - } - - for (i=0 ; i>2; - out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2; - out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2; - out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2; - } - } -} - - -static void R_MipMapLuminanceAlpha (const byte *in, byte *out, int width, int height) -{ - int i, j, row; - - if ( width == 1 && height == 1 ) { - return; - } - - row = width * 4; - width >>= 1; - height >>= 1; - - if ( width == 0 || height == 0 ) { - width += height; // get largest - for (i=0 ; i> 1; - out[3] = (in[3] + in[7]) >> 1; - } - return; - } - - for (i=0 ; i> 2; - out[3] = (in[3] + in[7] + in[row+3] + in[row+7]) >> 2; - } - } - -} - - -static void R_MipMapNormalHeight (const byte *in, byte *out, int width, int height, qboolean swizzle) -{ - int i, j; - int row; - int sx = swizzle ? 3 : 0; - int sa = swizzle ? 0 : 3; - - if ( width == 1 && height == 1 ) { - return; - } - - row = width * 4; - width >>= 1; - height >>= 1; - - for (i=0 ; i> 9; - data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9; - data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9; - } -} - -byte mipBlendColors[16][4] = { - {0,0,0,0}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, -}; - -static void RawImage_SwizzleRA( byte *data, int width, int height ) -{ - int i; - byte *ptr = data, swap; - - for (i=0; iinteger && scaled_width > width ) - scaled_width >>= 1; - if ( r_roundImagesDown->integer && scaled_height > height ) - scaled_height >>= 1; - - if ( picmip && data && resampledBuffer && r_imageUpsample->integer && - scaled_width < r_imageUpsampleMaxSize->integer && scaled_height < r_imageUpsampleMaxSize->integer) - { - int finalwidth, finalheight; - //int startTime, endTime; - - //startTime = ri.Milliseconds(); - - finalwidth = scaled_width << r_imageUpsample->integer; - finalheight = scaled_height << r_imageUpsample->integer; - - while ( finalwidth > r_imageUpsampleMaxSize->integer - || finalheight > r_imageUpsampleMaxSize->integer ) { - finalwidth >>= 1; - finalheight >>= 1; - } - - while ( finalwidth > glConfig.maxTextureSize - || finalheight > glConfig.maxTextureSize ) { - finalwidth >>= 1; - finalheight >>= 1; - } - - *resampledBuffer = ri.Hunk_AllocateTempMemory( finalwidth * finalheight * 4 ); - - if (scaled_width != width || scaled_height != height) - { - ResampleTexture (*data, width, height, *resampledBuffer, scaled_width, scaled_height); - } - else - { - byte *inbyte, *outbyte; - int i; - - inbyte = *data; - outbyte = *resampledBuffer; - - for (i = width * height * 4; i > 0; i--) - { - *outbyte++ = *inbyte++; - } - } - - if (type == IMGTYPE_COLORALPHA) - RGBAtoYCoCgA(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height); - - while (scaled_width < finalwidth || scaled_height < finalheight) - { - scaled_width <<= 1; - scaled_height <<= 1; - - FCBIByBlock(*resampledBuffer, scaled_width, scaled_height, clampToEdge, (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)); - } - - if (type == IMGTYPE_COLORALPHA) - { - YCoCgAtoRGBA(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height); - } - else if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) - { - FillInNormalizedZ(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height); - } - - - //endTime = ri.Milliseconds(); - - //ri.Printf(PRINT_ALL, "upsampled %dx%d to %dx%d in %dms\n", width, height, scaled_width, scaled_height, endTime - startTime); - - *data = *resampledBuffer; - width = scaled_width; - height = scaled_height; - } - else if ( scaled_width != width || scaled_height != height ) { - if (data && resampledBuffer) - { - *resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 ); - ResampleTexture (*data, width, height, *resampledBuffer, scaled_width, scaled_height); - *data = *resampledBuffer; - } - width = scaled_width; - height = scaled_height; - } - - // - // perform optional picmip operation - // - if ( picmip ) { - scaled_width >>= r_picmip->integer; - scaled_height >>= r_picmip->integer; - } - - // - // clamp to minimum size - // - if (scaled_width < 1) { - scaled_width = 1; - } - if (scaled_height < 1) { - scaled_height = 1; - } - - // - // clamp to the current upper OpenGL limit - // scale both axis down equally so we don't have to - // deal with a half mip resampling - // - while ( scaled_width > glConfig.maxTextureSize - || scaled_height > glConfig.maxTextureSize ) { - scaled_width >>= 1; - scaled_height >>= 1; - } - - *inout_width = width; - *inout_height = height; - *inout_scaled_width = scaled_width; - *inout_scaled_height = scaled_height; -} - - -static qboolean RawImage_HasAlpha(const byte *scan, int numPixels) -{ - int i; - - if (!scan) - return qtrue; - - for ( i = 0; i < numPixels; i++ ) - { - if ( scan[i*4 + 3] != 255 ) - { - return qtrue; - } - } - - return qfalse; -} - -static GLenum RawImage_GetFormat(const byte *data, int numPixels, qboolean lightMap, imgType_t type, imgFlags_t flags) -{ - int samples = 3; - GLenum internalFormat = GL_RGB; - qboolean forceNoCompression = (flags & IMGFLAG_NO_COMPRESSION); - qboolean normalmap = (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT); - - if(normalmap) - { - if ((!RawImage_HasAlpha(data, numPixels) || (type == IMGTYPE_NORMAL)) && !forceNoCompression && (glRefConfig.textureCompression & TCR_LATC)) - { - internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT; - } - else - { - if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB ) - { - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - } - else if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGBA4; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGBA8; - } - else - { - internalFormat = GL_RGBA; - } - } - } - else if(lightMap) - { - if(r_greyscale->integer) - internalFormat = GL_LUMINANCE; - else - internalFormat = GL_RGBA; - } - else - { - if (RawImage_HasAlpha(data, numPixels)) - { - samples = 4; - } - - // select proper internal format - if ( samples == 3 ) - { - if(r_greyscale->integer) - { - if(r_texturebits->integer == 16) - internalFormat = GL_LUMINANCE8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16; - else - internalFormat = GL_LUMINANCE; - } - else - { - if ( !forceNoCompression && (glRefConfig.textureCompression & TCR_BPTC) ) - { - internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; - } - else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB ) - { - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - } - else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC ) - { - internalFormat = GL_RGB4_S3TC; - } - else if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGB5; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGB8; - } - else - { - internalFormat = GL_RGB; - } - } - } - else if ( samples == 4 ) - { - if(r_greyscale->integer) - { - if(r_texturebits->integer == 16) - internalFormat = GL_LUMINANCE8_ALPHA8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16_ALPHA16; - else - internalFormat = GL_LUMINANCE_ALPHA; - } - else - { - if ( !forceNoCompression && (glRefConfig.textureCompression & TCR_BPTC) ) - { - internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; - } - else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB ) - { - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - } - else if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGBA4; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGBA8; - } - else - { - internalFormat = GL_RGBA; - } - } - } - - if (glRefConfig.textureSrgb && (flags & IMGFLAG_SRGB)) - { - switch(internalFormat) - { - case GL_RGB: - internalFormat = GL_SRGB_EXT; - break; - - case GL_RGB4: - case GL_RGB5: - case GL_RGB8: - internalFormat = GL_SRGB8_EXT; - break; - - case GL_RGBA: - internalFormat = GL_SRGB_ALPHA_EXT; - break; - - case GL_RGBA4: - case GL_RGBA8: - internalFormat = GL_SRGB8_ALPHA8_EXT; - break; - - case GL_LUMINANCE: - internalFormat = GL_SLUMINANCE_EXT; - break; - - case GL_LUMINANCE8: - case GL_LUMINANCE16: - internalFormat = GL_SLUMINANCE8_EXT; - break; - - case GL_LUMINANCE_ALPHA: - internalFormat = GL_SLUMINANCE_ALPHA_EXT; - break; - - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE16_ALPHA16: - internalFormat = GL_SLUMINANCE8_ALPHA8_EXT; - break; - - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; - break; - - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; - break; - - case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: - internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB; - break; - } - } - } - - return internalFormat; -} - - -static void RawImage_UploadTexture( byte *data, int x, int y, int width, int height, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture ) -{ - int dataFormat, dataType; - - switch(internalFormat) - { - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16_ARB: - case GL_DEPTH_COMPONENT24_ARB: - case GL_DEPTH_COMPONENT32_ARB: - dataFormat = GL_DEPTH_COMPONENT; - dataType = GL_UNSIGNED_BYTE; - break; - case GL_RGBA16F_ARB: - dataFormat = GL_RGBA; - dataType = GL_HALF_FLOAT_ARB; - break; - default: - dataFormat = GL_RGBA; - dataType = GL_UNSIGNED_BYTE; - break; - } - - if ( subtexture ) - qglTexSubImage2D( GL_TEXTURE_2D, 0, x, y, width, height, dataFormat, dataType, data ); - else - qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, dataFormat, dataType, data ); - - if (flags & IMGFLAG_MIPMAP) - { - int miplevel; - - miplevel = 0; - while (width > 1 || height > 1) - { - if (data) - { - if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) - { - if (internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) - { - R_MipMapLuminanceAlpha( data, data, width, height ); - } - else - { - R_MipMapNormalHeight( data, data, width, height, qtrue); - } - } - else if (flags & IMGFLAG_SRGB) - { - R_MipMapsRGB( data, width, height ); - } - else - { - R_MipMap( data, width, height ); - } - } - - width >>= 1; - height >>= 1; - if (width < 1) - width = 1; - if (height < 1) - height = 1; - miplevel++; - - if ( data && r_colorMipLevels->integer ) - R_BlendOverTexture( (byte *)data, width * height, mipBlendColors[miplevel] ); - - if ( subtexture ) - { - x >>= 1; - y >>= 1; - qglTexSubImage2D( GL_TEXTURE_2D, miplevel, x, y, width, height, dataFormat, dataType, data ); - } - else - { - qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, width, height, 0, dataFormat, dataType, data ); - } - } - } -} - - -/* -=============== -Upload32 - -=============== -*/ -extern qboolean charSet; -static void Upload32( byte *data, int width, int height, imgType_t type, imgFlags_t flags, - qboolean lightMap, GLenum internalFormat, int *pUploadWidth, int *pUploadHeight) -{ - byte *scaledBuffer = NULL; - byte *resampledBuffer = NULL; - int scaled_width, scaled_height; - int i, c; - byte *scan; - - RawImage_ScaleToPower2(&data, &width, &height, &scaled_width, &scaled_height, type, flags, &resampledBuffer); - - scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height ); - - // - // scan the texture for each channel's max values - // and verify if the alpha channel is being used or not - // - c = width*height; - scan = data; - - if( r_greyscale->integer ) - { - for ( i = 0; i < c; i++ ) - { - byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = luma; - scan[i*4 + 1] = luma; - scan[i*4 + 2] = luma; - } - } - else if( r_greyscale->value ) - { - for ( i = 0; i < c; i++ ) - { - float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value); - scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value); - scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value); - } - } - - // Convert to RGB if sRGB textures aren't supported in hardware - if (!glRefConfig.textureSrgb && (flags & IMGFLAG_SRGB)) - { - byte *in = data; - int c = width * height; - while (c--) - { - for (i = 0; i < 3; i++) - { - float x = ByteToFloat(in[i]); - x = sRGBtoRGB(x); - in[i] = FloatToByte(x); - } - in += 4; - } - - // FIXME: Probably should mark the image as non-sRGB as well - flags &= ~IMGFLAG_SRGB; - } - - // normals are always swizzled - if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) - { - RawImage_SwizzleRA(data, width, height); - } - - // LATC2 is only used for normals - if (internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) - { - byte *in = data; - int c = width * height; - while (c--) - { - in[0] = in[1]; - in[2] = in[1]; - in += 4; - } - } - - // copy or resample data as appropriate for first MIP level - if ( ( scaled_width == width ) && - ( scaled_height == height ) ) { - if (!(flags & IMGFLAG_MIPMAP)) - { - RawImage_UploadTexture( data, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse ); - //qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - - goto done; - } - Com_Memcpy (scaledBuffer, data, width*height*4); - } - else - { - // use the normal mip-mapping function to go down from here - while ( width > scaled_width || height > scaled_height ) { - - if (flags & IMGFLAG_SRGB) - { - R_MipMapsRGB( (byte *)data, width, height ); - } - else - { - R_MipMap( (byte *)data, width, height ); - } - - width >>= 1; - height >>= 1; - if ( width < 1 ) { - width = 1; - } - if ( height < 1 ) { - height = 1; - } - } - Com_Memcpy( scaledBuffer, data, width * height * 4 ); - } - - if (!(flags & IMGFLAG_NOLIGHTSCALE)) - R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !(flags & IMGFLAG_MIPMAP) ); - - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - - RawImage_UploadTexture(scaledBuffer, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse); - -done: - - if (flags & IMGFLAG_MIPMAP) - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - (GLint)Com_Clamp( 1, maxAnisotropy, r_ext_max_anisotropy->integer ) ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - else - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - - GL_CheckErrors(); - - if ( scaledBuffer != 0 ) - ri.Hunk_FreeTempMemory( scaledBuffer ); - if ( resampledBuffer != 0 ) - ri.Hunk_FreeTempMemory( resampledBuffer ); -} - - -static void EmptyTexture( int width, int height, imgType_t type, imgFlags_t flags, - qboolean lightMap, GLenum internalFormat, int *pUploadWidth, int *pUploadHeight ) -{ - int scaled_width, scaled_height; - - RawImage_ScaleToPower2(NULL, &width, &height, &scaled_width, &scaled_height, type, flags, NULL); - - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - - RawImage_UploadTexture(NULL, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse); - - if (flags & IMGFLAG_MIPMAP) - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - (GLint)Com_Clamp( 1, maxAnisotropy, r_ext_max_anisotropy->integer ) ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - else - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - - // Fix for sampling depth buffer on old nVidia cards - // from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844 - switch(internalFormat) - { - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16_ARB: - case GL_DEPTH_COMPONENT24_ARB: - case GL_DEPTH_COMPONENT32_ARB: - qglTexParameterf(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - break; - default: - break; - } - - GL_CheckErrors(); -} - - -/* -================ -R_CreateImage - -This is the only way any image_t are created -================ -*/ -image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgType_t type, imgFlags_t flags, int internalFormat ) { - image_t *image; - qboolean isLightmap = qfalse; - long hash; - int glWrapClampMode; - - if (strlen(name) >= MAX_QPATH ) { - ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name); - } - if ( !strncmp( name, "*lightmap", 9 ) ) { - isLightmap = qtrue; - } - - if ( tr.numImages == MAX_DRAWIMAGES ) { - ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit"); - } - - image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low ); - image->texnum = 1024 + tr.numImages; - tr.numImages++; - - image->type = type; - image->flags = flags; - - strcpy (image->imgName, name); - - image->width = width; - image->height = height; - if (flags & IMGFLAG_CLAMPTOEDGE) - glWrapClampMode = GL_CLAMP_TO_EDGE; - else - glWrapClampMode = GL_REPEAT; - - if (!internalFormat) - { - if (image->flags & IMGFLAG_CUBEMAP) - internalFormat = GL_RGBA8; - else - internalFormat = RawImage_GetFormat(pic, width * height, isLightmap, image->type, image->flags); - } - - image->internalFormat = internalFormat; - - - // lightmaps are always allocated on TMU 1 - if ( qglActiveTextureARB && isLightmap ) { - image->TMU = 1; - } else { - image->TMU = 0; - } - - if ( qglActiveTextureARB ) { - GL_SelectTexture( image->TMU ); - } - - if (image->flags & IMGFLAG_CUBEMAP) - { - GL_Bind(image); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - if (image->flags & IMGFLAG_MIPMAP) - { - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - else - { - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - - qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - - if (image->flags & IMGFLAG_MIPMAP) - qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP); - - image->uploadWidth = width; - image->uploadHeight = height; - } - else - { - GL_Bind(image); - - if (pic) - { - Upload32( pic, image->width, image->height, image->type, image->flags, - isLightmap, image->internalFormat, &image->uploadWidth, - &image->uploadHeight ); - } - else - { - EmptyTexture(image->width, image->height, image->type, image->flags, - isLightmap, image->internalFormat, &image->uploadWidth, - &image->uploadHeight ); - } - - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode ); - } - - GL_SelectTexture( 0 ); - - hash = generateHashValue(name); - image->next = hashTable[hash]; - hashTable[hash] = image; - - return image; -} - -void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height ) -{ - byte *scaledBuffer = NULL; - byte *resampledBuffer = NULL; - int scaled_width, scaled_height, scaled_x, scaled_y; - byte *data = pic; - - // normals are always swizzled - if (image->type == IMGTYPE_NORMAL || image->type == IMGTYPE_NORMALHEIGHT) - { - RawImage_SwizzleRA(pic, width, height); - } - - // LATC2 is only used for normals - if (image->internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) - { - byte *in = data; - int c = width * height; - while (c--) - { - in[0] = in[1]; - in[2] = in[1]; - in += 4; - } - } - - - RawImage_ScaleToPower2(&pic, &width, &height, &scaled_width, &scaled_height, image->type, image->flags, &resampledBuffer); - - scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height ); - - if ( qglActiveTextureARB ) { - GL_SelectTexture( image->TMU ); - } - - GL_Bind(image); - - // copy or resample data as appropriate for first MIP level - if ( ( scaled_width == width ) && - ( scaled_height == height ) ) { - if (!(image->flags & IMGFLAG_MIPMAP)) - { - scaled_x = x * scaled_width / width; - scaled_y = y * scaled_height / height; - RawImage_UploadTexture( data, scaled_x, scaled_y, scaled_width, scaled_height, image->internalFormat, image->type, image->flags, qtrue ); - //qglTexSubImage2D( GL_TEXTURE_2D, 0, scaled_x, scaled_y, scaled_width, scaled_height, GL_RGBA, GL_UNSIGNED_BYTE, data ); - - GL_CheckErrors(); - goto done; - } - Com_Memcpy (scaledBuffer, data, width*height*4); - } - else - { - // use the normal mip-mapping function to go down from here - while ( width > scaled_width || height > scaled_height ) { - - if (image->flags & IMGFLAG_SRGB) - { - R_MipMapsRGB( (byte *)data, width, height ); - } - else - { - R_MipMap( (byte *)data, width, height ); - } - - width >>= 1; - height >>= 1; - x >>= 1; - y >>= 1; - if ( width < 1 ) { - width = 1; - } - if ( height < 1 ) { - height = 1; - } - } - Com_Memcpy( scaledBuffer, data, width * height * 4 ); - } - - if (!(image->flags & IMGFLAG_NOLIGHTSCALE)) - R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !(image->flags & IMGFLAG_MIPMAP) ); - - scaled_x = x * scaled_width / width; - scaled_y = y * scaled_height / height; - RawImage_UploadTexture( (byte *)data, scaled_x, scaled_y, scaled_width, scaled_height, image->internalFormat, image->type, image->flags, qtrue ); - -done: - - GL_SelectTexture( 0 ); - - GL_CheckErrors(); - - if ( scaledBuffer != 0 ) - ri.Hunk_FreeTempMemory( scaledBuffer ); - if ( resampledBuffer != 0 ) - ri.Hunk_FreeTempMemory( resampledBuffer ); -} - -//=================================================================== - -typedef struct -{ - char *ext; - void (*ImageLoader)( const char *, unsigned char **, int *, int * ); -} imageExtToLoaderMap_t; - -// Note that the ordering indicates the order of preference used -// when there are multiple images of different formats available -static imageExtToLoaderMap_t imageLoaders[ ] = -{ - { "tga", R_LoadTGA }, - { "jpg", R_LoadJPG }, - { "jpeg", R_LoadJPG }, - { "png", R_LoadPNG }, - { "pcx", R_LoadPCX }, - { "bmp", R_LoadBMP } -}; - -static int numImageLoaders = ARRAY_LEN( imageLoaders ); - -/* -================= -R_LoadImage - -Loads any of the supported image types into a cannonical -32 bit format. -================= -*/ -void R_LoadImage( const char *name, byte **pic, int *width, int *height ) -{ - qboolean orgNameFailed = qfalse; - int orgLoader = -1; - int i; - char localName[ MAX_QPATH ]; - const char *ext; - char *altName; - - *pic = NULL; - *width = 0; - *height = 0; - - Q_strncpyz( localName, name, MAX_QPATH ); - - ext = COM_GetExtension( localName ); - - if( *ext ) - { - // Look for the correct loader and use it - for( i = 0; i < numImageLoaders; i++ ) - { - if( !Q_stricmp( ext, imageLoaders[ i ].ext ) ) - { - // Load - imageLoaders[ i ].ImageLoader( localName, pic, width, height ); - break; - } - } - - // A loader was found - if( i < numImageLoaders ) - { - if( *pic == NULL ) - { - // Loader failed, most likely because the file isn't there; - // try again without the extension - orgNameFailed = qtrue; - orgLoader = i; - COM_StripExtension( name, localName, MAX_QPATH ); - } - else - { - // Something loaded - return; - } - } - } - - // Try and find a suitable match using all - // the image formats supported - for( i = 0; i < numImageLoaders; i++ ) - { - if (i == orgLoader) - continue; - - altName = va( "%s.%s", localName, imageLoaders[ i ].ext ); - - // Load - imageLoaders[ i ].ImageLoader( altName, pic, width, height ); - - if( *pic ) - { - if( orgNameFailed ) - { - ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n", - name, altName ); - } - - break; - } - } -} - - -/* -=============== -R_FindImageFile - -Finds or loads the given image. -Returns NULL if it fails, not a default image. -============== -*/ -image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) -{ - image_t *image; - int width, height; - byte *pic; - long hash; - - if (!name) { - return NULL; - } - - hash = generateHashValue(name); - - // - // see if the image is already loaded - // - for (image=hashTable[hash]; image; image=image->next) { - if ( !strcmp( name, image->imgName ) ) { - // the white image can be used with any set of parms, but other mismatches are errors - if ( strcmp( name, "*white" ) ) { - if ( image->flags != flags ) { - ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed flags (%i vs %i)\n", name, image->flags, flags ); - } - } - return image; - } - } - - // - // load the pic from disk - // - R_LoadImage( name, &pic, &width, &height ); - if ( pic == NULL ) { - return NULL; - } - - if (r_normalMapping->integer && !(type == IMGTYPE_NORMAL) && (flags & IMGFLAG_PICMIP) && (flags & IMGFLAG_MIPMAP) && (flags & IMGFLAG_GENNORMALMAP)) - { - char normalName[MAX_QPATH]; - image_t *normalImage; - int normalWidth, normalHeight; - imgFlags_t normalFlags; - - normalFlags = (flags & ~(IMGFLAG_GENNORMALMAP | IMGFLAG_SRGB)) | IMGFLAG_NOLIGHTSCALE; - - COM_StripExtension(name, normalName, MAX_QPATH); - Q_strcat(normalName, MAX_QPATH, "_n"); - - // find normalmap in case it's there - normalImage = R_FindImageFile(normalName, IMGTYPE_NORMAL, normalFlags); - - // if not, generate it - if (normalImage == NULL) - { - byte *normalPic; - int x, y; - - normalWidth = width; - normalHeight = height; - normalPic = ri.Malloc(width * height * 4); - RGBAtoNormal(pic, normalPic, width, height, flags & IMGFLAG_CLAMPTOEDGE); - -#if 1 - // Brighten up the original image to work with the normal map - RGBAtoYCoCgA(pic, pic, width, height); - for (y = 0; y < height; y++) - { - byte *picbyte = pic + y * width * 4; - byte *normbyte = normalPic + y * width * 4; - for (x = 0; x < width; x++) - { - int div = MAX(normbyte[2] - 127, 16); - picbyte[0] = CLAMP(picbyte[0] * 128 / div, 0, 255); - picbyte += 4; - normbyte += 4; - } - } - YCoCgAtoRGBA(pic, pic, width, height); -#else - // Blur original image's luma to work with the normal map - { - byte *blurPic; - - RGBAtoYCoCgA(pic, pic, width, height); - blurPic = ri.Malloc(width * height); - - for (y = 1; y < height - 1; y++) - { - byte *picbyte = pic + y * width * 4; - byte *blurbyte = blurPic + y * width; - - picbyte += 4; - blurbyte += 1; - - for (x = 1; x < width - 1; x++) - { - int result; - - result = *(picbyte - (width + 1) * 4) + *(picbyte - width * 4) + *(picbyte - (width - 1) * 4) + - *(picbyte - 1 * 4) + *(picbyte ) + *(picbyte + 1 * 4) + - *(picbyte + (width - 1) * 4) + *(picbyte + width * 4) + *(picbyte + (width + 1) * 4); - - result /= 9; - - *blurbyte = result; - picbyte += 4; - blurbyte += 1; - } - } - - // FIXME: do borders - - for (y = 1; y < height - 1; y++) - { - byte *picbyte = pic + y * width * 4; - byte *blurbyte = blurPic + y * width; - - picbyte += 4; - blurbyte += 1; - - for (x = 1; x < width - 1; x++) - { - picbyte[0] = *blurbyte; - picbyte += 4; - blurbyte += 1; - } - } - - ri.Free(blurPic); - - YCoCgAtoRGBA(pic, pic, width, height); - } -#endif - - R_CreateImage( normalName, normalPic, normalWidth, normalHeight, IMGTYPE_NORMAL, normalFlags, 0 ); - ri.Free( normalPic ); - } - } - - image = R_CreateImage( ( char * ) name, pic, width, height, type, flags, 0 ); - ri.Free( pic ); - return image; -} - - -/* -================ -R_CreateDlightImage -================ -*/ -#define DLIGHT_SIZE 16 -static void R_CreateDlightImage( void ) { - int x,y; - byte data[DLIGHT_SIZE][DLIGHT_SIZE][4]; - int b; - - // make a centered inverse-square falloff blob for dynamic lighting - for (x=0 ; x 255) { - b = 255; - } else if ( b < 75 ) { - b = 0; - } - data[y][x][0] = - data[y][x][1] = - data[y][x][2] = b; - data[y][x][3] = 255; - } - } - tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 ); -} - - -/* -================= -R_InitFogTable -================= -*/ -void R_InitFogTable( void ) { - int i; - float d; - float exp; - - exp = 0.5; - - for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) { - d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp ); - - tr.fogTable[i] = d; - } -} - -/* -================ -R_FogFactor - -Returns a 0.0 to 1.0 fog density value -This is called for each texel of the fog texture on startup -and for each vertex of transparent shaders in fog dynamically -================ -*/ -float R_FogFactor( float s, float t ) { - float d; - - s -= 1.0/512; - if ( s < 0 ) { - return 0; - } - if ( t < 1.0/32 ) { - return 0; - } - if ( t < 31.0/32 ) { - s *= (t - 1.0f/32.0f) / (30.0f/32.0f); - } - - // we need to leave a lot of clamp range - s *= 8; - - if ( s > 1.0 ) { - s = 1.0; - } - - d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ]; - - return d; -} - -/* -================ -R_CreateFogImage -================ -*/ -#define FOG_S 256 -#define FOG_T 32 -static void R_CreateFogImage( void ) { - int x,y; - byte *data; - float d; - float borderColor[4]; - - data = ri.Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 ); - - // S is distance, T is depth - for (x=0 ; xinteger >= 2) - { - for( x = 0; x < MAX_DLIGHTS; x++) - { - tr.shadowCubemaps[x] = R_CreateImage(va("*shadowcubemap%i", x), (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE | IMGFLAG_CUBEMAP, 0); - } - } - - // with overbright bits active, we need an image which is some fraction of full color, - // for default lightmaps, etc - for (x=0 ; xinteger && glRefConfig.framebufferObject && glRefConfig.textureFloat) - hdrFormat = GL_RGBA16F_ARB; - - rgbFormat = GL_RGBA8; - - tr.renderImage = R_CreateImage("_render", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); - - if (r_drawSunRays->integer) - tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat); - - if (glRefConfig.framebufferObject) - { - tr.renderDepthImage = R_CreateImage("*renderdepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); - tr.textureDepthImage = R_CreateImage("*texturedepth", NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); - } - - { - unsigned short sdata[4]; - void *p; - - if (hdrFormat == GL_RGBA16F_ARB) - { - sdata[0] = FloatToHalf(0.0f); - sdata[1] = FloatToHalf(0.45f); - sdata[2] = FloatToHalf(1.0f); - sdata[3] = FloatToHalf(1.0f); - p = &sdata[0]; - } - else - { - data[0][0][0] = 0; - data[0][0][1] = 0.45f * 255; - data[0][0][2] = 255; - data[0][0][3] = 255; - p = data; - } - - tr.calcLevelsImage = R_CreateImage("*calcLevels", p, 1, 1, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); - tr.targetLevelsImage = R_CreateImage("*targetLevels", p, 1, 1, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); - tr.fixedLevelsImage = R_CreateImage("*fixedLevels", p, 1, 1, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); - } - - for (x = 0; x < 2; x++) - { - tr.textureScratchImage[x] = R_CreateImage(va("*textureScratch%d", x), NULL, 256, 256, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - } - for (x = 0; x < 2; x++) - { - tr.quarterImage[x] = R_CreateImage(va("*quarter%d", x), NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - } - - if (r_ssao->integer) - { - tr.screenSsaoImage = R_CreateImage("*screenSsao", NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB); - } - - if (r_shadows->integer == 4) - { - for( x = 0; x < MAX_DRAWN_PSHADOWS; x++) - { - tr.pshadowMaps[x] = R_CreateImage(va("*shadowmap%i", x), NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - } - } - - if (r_sunlightMode->integer) - { - for ( x = 0; x < 3; x++) - { - tr.sunShadowDepthImage[x] = R_CreateImage(va("*sunshadowdepth%i", x), NULL, r_shadowMapSize->integer, r_shadowMapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); - } - - tr.screenShadowImage = R_CreateImage("*screenShadow", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - } - - if (r_cubeMapping->integer) - { - tr.renderCubeImage = R_CreateImage("*renderCube", NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, rgbFormat); - } - } -} - - -/* -=============== -R_SetColorMappings -=============== -*/ -void R_SetColorMappings( void ) { - int i, j; - float g; - int inf; - int shift; - - // setup the overbright lighting - tr.overbrightBits = r_overBrightBits->integer; - if ( !glConfig.deviceSupportsGamma ) { - tr.overbrightBits = 0; // need hardware gamma for overbright - } - - // never overbright in windowed mode without soft overbright - if ( !glConfig.isFullscreen && !r_softOverbright->integer ) - { - tr.overbrightBits = 0; - } - - // never overbright with tonemapping - if ( r_toneMap->integer && r_hdr->integer ) - { - tr.overbrightBits = 0; - } - - // allow 2 overbright bits in 24 bit, but only 1 in 16 bit - if ( glConfig.colorBits > 16 ) { - if ( tr.overbrightBits > 2 ) { - tr.overbrightBits = 2; - } - } else { - if ( tr.overbrightBits > 1 ) { - tr.overbrightBits = 1; - } - } - if ( tr.overbrightBits < 0 ) { - tr.overbrightBits = 0; - } - - tr.identityLight = 1.0f / ( 1 << tr.overbrightBits ); - tr.identityLightByte = 255 * tr.identityLight; - - - if ( r_intensity->value <= 1 ) { - ri.Cvar_Set( "r_intensity", "1" ); - } - - if ( r_gamma->value < 0.5f ) { - ri.Cvar_Set( "r_gamma", "0.5" ); - } else if ( r_gamma->value > 3.0f ) { - ri.Cvar_Set( "r_gamma", "3.0" ); - } - - g = r_gamma->value; - - shift = tr.overbrightBits; - - // no shift with soft overbright - if (r_softOverbright->integer) - { - shift = 0; - } - - for ( i = 0; i < 256; i++ ) { - int i2; - - if (r_srgb->integer) - { - i2 = 255 * RGBtosRGB(i/255.0f) + 0.5f; - } - else - { - i2 = i; - } - - if ( g == 1 ) { - inf = i2; - } else { - inf = 255 * pow ( i2/255.0f, 1.0f / g ) + 0.5f; - } - inf <<= shift; - if (inf < 0) { - inf = 0; - } - if (inf > 255) { - inf = 255; - } - s_gammatable[i] = inf; - } - - for (i=0 ; i<256 ; i++) { - j = i * r_intensity->value; - if (j > 255) { - j = 255; - } - s_intensitytable[i] = j; - } - - if ( glConfig.deviceSupportsGamma ) - { - GLimp_SetGamma( s_gammatable, s_gammatable, s_gammatable ); - } -} - -/* -=============== -R_InitImages -=============== -*/ -void R_InitImages( void ) { - Com_Memset(hashTable, 0, sizeof(hashTable)); - // build brightness translation tables - R_SetColorMappings(); - - // create default texture and white texture - R_CreateBuiltinImages(); -} - -/* -=============== -R_DeleteTextures -=============== -*/ -void R_DeleteTextures( void ) { - int i; - - for ( i=0; itexnum ); - } - Com_Memset( tr.images, 0, sizeof( tr.images ) ); - - tr.numImages = 0; - - Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) ); - if ( qglActiveTextureARB ) { - GL_SelectTexture( 1 ); - qglBindTexture( GL_TEXTURE_2D, 0 ); - GL_SelectTexture( 0 ); - qglBindTexture( GL_TEXTURE_2D, 0 ); - } else { - qglBindTexture( GL_TEXTURE_2D, 0 ); - } -} - -/* -============================================================================ - -SKINS - -============================================================================ -*/ - -/* -================== -CommaParse - -This is unfortunate, but the skin files aren't -compatable with our normal parsing rules. -================== -*/ -static char *CommaParse( char **data_p ) { - int c = 0, len; - char *data; - static char com_token[MAX_TOKEN_CHARS]; - - data = *data_p; - len = 0; - com_token[0] = 0; - - // make sure incoming data is valid - if ( !data ) { - *data_p = NULL; - return com_token; - } - - while ( 1 ) { - // skip whitespace - while( (c = *data) <= ' ') { - if( !c ) { - break; - } - data++; - } - - - c = *data; - - // skip double slash comments - if ( c == '/' && data[1] == '/' ) - { - while (*data && *data != '\n') - data++; - } - // skip /* */ comments - else if ( c=='/' && data[1] == '*' ) - { - while ( *data && ( *data != '*' || data[1] != '/' ) ) - { - data++; - } - if ( *data ) - { - data += 2; - } - } - else - { - break; - } - } - - if ( c == 0 ) { - return ""; - } - - // handle quoted strings - if (c == '\"') - { - data++; - while (1) - { - c = *data++; - if (c=='\"' || !c) - { - com_token[len] = 0; - *data_p = ( char * ) data; - return com_token; - } - if (len < MAX_TOKEN_CHARS) - { - com_token[len] = c; - len++; - } - } - } - - // parse a regular word - do - { - if (len < MAX_TOKEN_CHARS) - { - com_token[len] = c; - len++; - } - data++; - c = *data; - } while (c>32 && c != ',' ); - - if (len == MAX_TOKEN_CHARS) - { -// ri.Printf (PRINT_DEVELOPER, "Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS); - len = 0; - } - com_token[len] = 0; - - *data_p = ( char * ) data; - return com_token; -} - - -/* -=============== -RE_RegisterSkin - -=============== -*/ -qhandle_t RE_RegisterSkin( const char *name ) { - qhandle_t hSkin; - skin_t *skin; - skinSurface_t *surf; - union { - char *c; - void *v; - } text; - char *text_p; - char *token; - char surfName[MAX_QPATH]; - - if ( !name || !name[0] ) { - ri.Printf( PRINT_DEVELOPER, "Empty name passed to RE_RegisterSkin\n" ); - return 0; - } - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_DEVELOPER, "Skin name exceeds MAX_QPATH\n" ); - return 0; - } - - - // see if the skin is already loaded - for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) { - skin = tr.skins[hSkin]; - if ( !Q_stricmp( skin->name, name ) ) { - if( skin->numSurfaces == 0 ) { - return 0; // default skin - } - return hSkin; - } - } - - // allocate a new skin - if ( tr.numSkins == MAX_SKINS ) { - ri.Printf( PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name ); - return 0; - } - tr.numSkins++; - skin = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); - tr.skins[hSkin] = skin; - Q_strncpyz( skin->name, name, sizeof( skin->name ) ); - skin->numSurfaces = 0; - - R_IssuePendingRenderCommands(); - - // If not a .skin file, load as a single shader - if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) { - skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof(skin->surfaces[0]), h_low ); - skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue ); - return hSkin; - } - - // load and parse the skin file - ri.FS_ReadFile( name, &text.v ); - if ( !text.c ) { - return 0; - } - - text_p = text.c; - while ( text_p && *text_p ) { - // get surface name - token = CommaParse( &text_p ); - Q_strncpyz( surfName, token, sizeof( surfName ) ); - - if ( !token[0] ) { - break; - } - // lowercase the surface name so skin compares are faster - Q_strlwr( surfName ); - - if ( *text_p == ',' ) { - text_p++; - } - - if ( strstr( token, "tag_" ) ) { - continue; - } - - // parse the shader name - token = CommaParse( &text_p ); - - if ( skin->numSurfaces >= MD3_MAX_SURFACES ) { - ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MD3_MAX_SURFACES ); - break; - } - - surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); - Q_strncpyz( surf->name, surfName, sizeof( surf->name ) ); - surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue ); - skin->numSurfaces++; - } - - ri.FS_FreeFile( text.v ); - - - // never let a skin have 0 shaders - if ( skin->numSurfaces == 0 ) { - return 0; // use default skin - } - - return hSkin; -} - - -/* -=============== -R_InitSkins -=============== -*/ -void R_InitSkins( void ) { - skin_t *skin; - - tr.numSkins = 1; - - // make the default skin have all default shaders - skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); - Q_strncpyz( skin->name, "", sizeof( skin->name ) ); - skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low ); - skin->surfaces[0]->shader = tr.defaultShader; -} - -/* -=============== -R_GetSkinByHandle -=============== -*/ -skin_t *R_GetSkinByHandle( qhandle_t hSkin ) { - if ( hSkin < 1 || hSkin >= tr.numSkins ) { - return tr.skins[0]; - } - return tr.skins[ hSkin ]; -} - -/* -=============== -R_SkinList_f -=============== -*/ -void R_SkinList_f( void ) { - int i, j; - skin_t *skin; - - ri.Printf (PRINT_ALL, "------------------\n"); - - for ( i = 0 ; i < tr.numSkins ; i++ ) { - skin = tr.skins[i]; - - ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name ); - for ( j = 0 ; j < skin->numSurfaces ; j++ ) { - ri.Printf( PRINT_ALL, " %s = %s\n", - skin->surfaces[j]->name, skin->surfaces[j]->shader->name ); - } - } - ri.Printf (PRINT_ALL, "------------------\n"); -} - - diff --git a/code/renderergl2/tr_init.c b/code/renderergl2/tr_init.c deleted file mode 100644 index 00646be2ed..0000000000 --- a/code/renderergl2/tr_init.c +++ /dev/null @@ -1,1580 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_init.c -- functions that are not called every frame - -#include "tr_local.h" - -glconfig_t glConfig; -glRefConfig_t glRefConfig; -qboolean textureFilterAnisotropic = qfalse; -int maxAnisotropy = 0; -float displayAspect = 0.0f; - -glstate_t glState; - -static void GfxInfo_f( void ); -static void GfxMemInfo_f( void ); - -#ifdef USE_RENDERER_DLOPEN -cvar_t *com_altivec; -#endif - -cvar_t *r_flareSize; -cvar_t *r_flareFade; -cvar_t *r_flareCoeff; - -cvar_t *r_railWidth; -cvar_t *r_railCoreWidth; -cvar_t *r_railSegmentLength; - -cvar_t *r_verbose; -cvar_t *r_ignore; - -cvar_t *r_detailTextures; - -cvar_t *r_znear; -cvar_t *r_zproj; -cvar_t *r_stereoSeparation; - -cvar_t *r_skipBackEnd; - -cvar_t *r_stereoEnabled; -cvar_t *r_anaglyphMode; - -cvar_t *r_greyscale; - -cvar_t *r_ignorehwgamma; -cvar_t *r_measureOverdraw; - -cvar_t *r_inGameVideo; -cvar_t *r_fastsky; -cvar_t *r_drawSun; -cvar_t *r_dynamiclight; -cvar_t *r_dlightBacks; - -cvar_t *r_lodbias; -cvar_t *r_lodscale; - -cvar_t *r_norefresh; -cvar_t *r_drawentities; -cvar_t *r_drawworld; -cvar_t *r_speeds; -cvar_t *r_fullbright; -cvar_t *r_novis; -cvar_t *r_nocull; -cvar_t *r_facePlaneCull; -cvar_t *r_showcluster; -cvar_t *r_nocurves; - -cvar_t *r_allowExtensions; - -cvar_t *r_ext_compressed_textures; -cvar_t *r_ext_multitexture; -cvar_t *r_ext_compiled_vertex_array; -cvar_t *r_ext_texture_env_add; -cvar_t *r_ext_texture_filter_anisotropic; -cvar_t *r_ext_max_anisotropy; - -cvar_t *r_ext_draw_range_elements; -cvar_t *r_ext_multi_draw_arrays; -cvar_t *r_ext_framebuffer_object; -cvar_t *r_ext_texture_float; -cvar_t *r_arb_half_float_pixel; -cvar_t *r_ext_framebuffer_multisample; -cvar_t *r_arb_seamless_cube_map; -cvar_t *r_arb_vertex_type_2_10_10_10_rev; - -cvar_t *r_mergeMultidraws; -cvar_t *r_mergeLeafSurfaces; - -cvar_t *r_cameraExposure; - -cvar_t *r_softOverbright; - -cvar_t *r_hdr; -cvar_t *r_floatLightmap; -cvar_t *r_postProcess; - -cvar_t *r_toneMap; -cvar_t *r_forceToneMap; -cvar_t *r_forceToneMapMin; -cvar_t *r_forceToneMapAvg; -cvar_t *r_forceToneMapMax; - -cvar_t *r_autoExposure; -cvar_t *r_forceAutoExposure; -cvar_t *r_forceAutoExposureMin; -cvar_t *r_forceAutoExposureMax; - -cvar_t *r_srgb; - -cvar_t *r_depthPrepass; -cvar_t *r_ssao; - -cvar_t *r_normalMapping; -cvar_t *r_specularMapping; -cvar_t *r_deluxeMapping; -cvar_t *r_parallaxMapping; -cvar_t *r_cubeMapping; -cvar_t *r_deluxeSpecular; -cvar_t *r_specularIsMetallic; -cvar_t *r_baseSpecular; -cvar_t *r_baseGloss; -cvar_t *r_recalcMD3Normals; -cvar_t *r_mergeLightmaps; -cvar_t *r_dlightMode; -cvar_t *r_pshadowDist; -cvar_t *r_imageUpsample; -cvar_t *r_imageUpsampleMaxSize; -cvar_t *r_imageUpsampleType; -cvar_t *r_genNormalMaps; -cvar_t *r_forceSun; -cvar_t *r_forceSunMapLightScale; -cvar_t *r_forceSunLightScale; -cvar_t *r_forceSunAmbientScale; -cvar_t *r_sunlightMode; -cvar_t *r_drawSunRays; -cvar_t *r_sunShadows; -cvar_t *r_shadowFilter; -cvar_t *r_shadowMapSize; -cvar_t *r_shadowCascadeZNear; -cvar_t *r_shadowCascadeZFar; -cvar_t *r_shadowCascadeZBias; -cvar_t *r_ignoreDstAlpha; - -cvar_t *r_ignoreGLErrors; -cvar_t *r_logFile; - -cvar_t *r_stencilbits; -cvar_t *r_depthbits; -cvar_t *r_colorbits; -cvar_t *r_texturebits; -cvar_t *r_ext_multisample; - -cvar_t *r_drawBuffer; -cvar_t *r_lightmap; -cvar_t *r_vertexLight; -cvar_t *r_uiFullScreen; -cvar_t *r_shadows; -cvar_t *r_flares; -cvar_t *r_mode; -cvar_t *r_nobind; -cvar_t *r_singleShader; -cvar_t *r_roundImagesDown; -cvar_t *r_colorMipLevels; -cvar_t *r_picmip; -cvar_t *r_showtris; -cvar_t *r_showsky; -cvar_t *r_shownormals; -cvar_t *r_finish; -cvar_t *r_clear; -cvar_t *r_swapInterval; -cvar_t *r_textureMode; -cvar_t *r_offsetFactor; -cvar_t *r_offsetUnits; -cvar_t *r_gamma; -cvar_t *r_intensity; -cvar_t *r_lockpvs; -cvar_t *r_noportals; -cvar_t *r_portalOnly; - -cvar_t *r_subdivisions; -cvar_t *r_lodCurveError; - -cvar_t *r_fullscreen; -cvar_t *r_noborder; - -cvar_t *r_customwidth; -cvar_t *r_customheight; -cvar_t *r_customPixelAspect; - -cvar_t *r_overBrightBits; -cvar_t *r_mapOverBrightBits; - -cvar_t *r_debugSurface; -cvar_t *r_simpleMipMaps; - -cvar_t *r_showImages; - -cvar_t *r_ambientScale; -cvar_t *r_directedScale; -cvar_t *r_debugLight; -cvar_t *r_debugSort; -cvar_t *r_printShaders; -cvar_t *r_saveFontData; - -cvar_t *r_marksOnTriangleMeshes; - -cvar_t *r_aviMotionJpegQuality; -cvar_t *r_screenshotJpegQuality; - -cvar_t *r_maxpolys; -int max_polys; -cvar_t *r_maxpolyverts; -int max_polyverts; - -/* -** InitOpenGL -** -** This function is responsible for initializing a valid OpenGL subsystem. This -** is done by calling GLimp_Init (which gives us a working OGL subsystem) then -** setting variables, checking GL constants, and reporting the gfx system config -** to the user. -*/ -static void InitOpenGL( void ) -{ - char renderer_buffer[1024]; - - // - // initialize OS specific portions of the renderer - // - // GLimp_Init directly or indirectly references the following cvars: - // - r_fullscreen - // - r_mode - // - r_(color|depth|stencil)bits - // - r_ignorehwgamma - // - r_gamma - // - - if ( glConfig.vidWidth == 0 ) - { - GLint temp; - - GLimp_Init(); - GLimp_InitExtraExtensions(); - - strcpy( renderer_buffer, glConfig.renderer_string ); - Q_strlwr( renderer_buffer ); - - // OpenGL driver constants - qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp ); - glConfig.maxTextureSize = temp; - - // stubbed or broken drivers may have reported 0... - if ( glConfig.maxTextureSize <= 0 ) - { - glConfig.maxTextureSize = 0; - } - } - - // set default state - GL_SetDefaultState(); -} - -/* -================== -GL_CheckErrors -================== -*/ -void GL_CheckErrs( char *file, int line ) { - int err; - char s[64]; - - err = qglGetError(); - if ( err == GL_NO_ERROR ) { - return; - } - if ( r_ignoreGLErrors->integer ) { - return; - } - switch( err ) { - case GL_INVALID_ENUM: - strcpy( s, "GL_INVALID_ENUM" ); - break; - case GL_INVALID_VALUE: - strcpy( s, "GL_INVALID_VALUE" ); - break; - case GL_INVALID_OPERATION: - strcpy( s, "GL_INVALID_OPERATION" ); - break; - case GL_STACK_OVERFLOW: - strcpy( s, "GL_STACK_OVERFLOW" ); - break; - case GL_STACK_UNDERFLOW: - strcpy( s, "GL_STACK_UNDERFLOW" ); - break; - case GL_OUT_OF_MEMORY: - strcpy( s, "GL_OUT_OF_MEMORY" ); - break; - default: - Com_sprintf( s, sizeof(s), "%i", err); - break; - } - - ri.Error( ERR_FATAL, "GL_CheckErrors: %s in %s at line %d", s , file, line); -} - - -/* -** R_GetModeInfo -*/ -typedef struct vidmode_s -{ - const char *description; - int width, height; - float pixelAspect; // pixel width / height -} vidmode_t; - -vidmode_t r_vidModes[] = -{ - { "Mode 0: 320x240", 320, 240, 1 }, - { "Mode 1: 400x300", 400, 300, 1 }, - { "Mode 2: 512x384", 512, 384, 1 }, - { "Mode 3: 640x480", 640, 480, 1 }, - { "Mode 4: 800x600", 800, 600, 1 }, - { "Mode 5: 960x720", 960, 720, 1 }, - { "Mode 6: 1024x768", 1024, 768, 1 }, - { "Mode 7: 1152x864", 1152, 864, 1 }, - { "Mode 8: 1280x1024", 1280, 1024, 1 }, - { "Mode 9: 1600x1200", 1600, 1200, 1 }, - { "Mode 10: 2048x1536", 2048, 1536, 1 }, - { "Mode 11: 856x480 (wide)",856, 480, 1 } -}; -static int s_numVidModes = ARRAY_LEN( r_vidModes ); - -qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ) { - vidmode_t *vm; - float pixelAspect; - - if ( mode < -1 ) { - return qfalse; - } - if ( mode >= s_numVidModes ) { - return qfalse; - } - - if ( mode == -1 ) { - *width = r_customwidth->integer; - *height = r_customheight->integer; - pixelAspect = r_customPixelAspect->value; - } else { - vm = &r_vidModes[mode]; - - *width = vm->width; - *height = vm->height; - pixelAspect = vm->pixelAspect; - } - - *windowAspect = (float)*width / ( *height * pixelAspect ); - - return qtrue; -} - -/* -** R_ModeList_f -*/ -static void R_ModeList_f( void ) -{ - int i; - - ri.Printf( PRINT_ALL, "\n" ); - for ( i = 0; i < s_numVidModes; i++ ) - { - ri.Printf( PRINT_ALL, "%s\n", r_vidModes[i].description ); - } - ri.Printf( PRINT_ALL, "\n" ); -} - - -/* -============================================================================== - - SCREEN SHOTS - -NOTE TTimo -some thoughts about the screenshots system: -screenshots get written in fs_homepath + fs_gamedir -vanilla q3 .. baseq3/screenshots/ *.tga -team arena .. missionpack/screenshots/ *.tga - -two commands: "screenshot" and "screenshotJPEG" -we use statics to store a count and start writing the first screenshot/screenshot????.tga (.jpg) available -(with FS_FileExists / FS_FOpenFileWrite calls) -FIXME: the statics don't get a reinit between fs_game changes - -============================================================================== -*/ - -/* -================== -RB_ReadPixels - -Reads an image but takes care of alignment issues for reading RGB images. - -Reads a minimum offset for where the RGB data starts in the image from -integer stored at pointer offset. When the function has returned the actual -offset was written back to address offset. This address will always have an -alignment of packAlign to ensure efficient copying. - -Stores the length of padding after a line of pixels to address padlen - -Return value must be freed with ri.Hunk_FreeTempMemory() -================== -*/ - -byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *padlen) -{ - byte *buffer, *bufstart; - int padwidth, linelen; - GLint packAlign; - - qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); - - linelen = width * 3; - padwidth = PAD(linelen, packAlign); - - // Allocate a few more bytes so that we can choose an alignment we like - buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1); - - bufstart = PADP((intptr_t) buffer + *offset, packAlign); - qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart); - - *offset = bufstart - buffer; - *padlen = padwidth - linelen; - - return buffer; -} - -/* -================== -RB_TakeScreenshot -================== -*/ -void RB_TakeScreenshot(int x, int y, int width, int height, char *fileName) -{ - byte *allbuf, *buffer; - byte *srcptr, *destptr; - byte *endline, *endmem; - byte temp; - - int linelen, padlen; - size_t offset = 18, memcount; - - allbuf = RB_ReadPixels(x, y, width, height, &offset, &padlen); - buffer = allbuf + offset - 18; - - Com_Memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = width & 255; - buffer[13] = width >> 8; - buffer[14] = height & 255; - buffer[15] = height >> 8; - buffer[16] = 24; // pixel size - - // swap rgb to bgr and remove padding from line endings - linelen = width * 3; - - srcptr = destptr = allbuf + offset; - endmem = srcptr + (linelen + padlen) * height; - - while(srcptr < endmem) - { - endline = srcptr + linelen; - - while(srcptr < endline) - { - temp = srcptr[0]; - *destptr++ = srcptr[2]; - *destptr++ = srcptr[1]; - *destptr++ = temp; - - srcptr += 3; - } - - // Skip the pad - srcptr += padlen; - } - - memcount = linelen * height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(allbuf + offset, memcount); - - ri.FS_WriteFile(fileName, buffer, memcount + 18); - - ri.Hunk_FreeTempMemory(allbuf); -} - -/* -================== -RB_TakeScreenshotJPEG -================== -*/ - -void RB_TakeScreenshotJPEG(int x, int y, int width, int height, char *fileName) -{ - byte *buffer; - size_t offset = 0, memcount; - int padlen; - - buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen); - memcount = (width * 3 + padlen) * height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(buffer + offset, memcount); - - RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, buffer + offset, padlen); - ri.Hunk_FreeTempMemory(buffer); -} - -/* -================== -RB_TakeScreenshotCmd -================== -*/ -const void *RB_TakeScreenshotCmd( const void *data ) { - const screenshotCommand_t *cmd; - - cmd = (const screenshotCommand_t *)data; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - if (cmd->jpeg) - RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); - else - RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); - - return (const void *)(cmd + 1); -} - -/* -================== -R_TakeScreenshot -================== -*/ -void R_TakeScreenshot( int x, int y, int width, int height, char *name, qboolean jpeg ) { - static char fileName[MAX_OSPATH]; // bad things if two screenshots per frame? - screenshotCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SCREENSHOT; - - cmd->x = x; - cmd->y = y; - cmd->width = width; - cmd->height = height; - Q_strncpyz( fileName, name, sizeof(fileName) ); - cmd->fileName = fileName; - cmd->jpeg = jpeg; -} - -/* -================== -R_ScreenshotFilename -================== -*/ -void R_ScreenshotFilename( int lastNumber, char *fileName ) { - int a,b,c,d; - - if ( lastNumber < 0 || lastNumber > 9999 ) { - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.tga" ); - return; - } - - a = lastNumber / 1000; - lastNumber -= a*1000; - b = lastNumber / 100; - lastNumber -= b*100; - c = lastNumber / 10; - lastNumber -= c*10; - d = lastNumber; - - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.tga" - , a, b, c, d ); -} - -/* -================== -R_ScreenshotFilename -================== -*/ -void R_ScreenshotFilenameJPEG( int lastNumber, char *fileName ) { - int a,b,c,d; - - if ( lastNumber < 0 || lastNumber > 9999 ) { - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.jpg" ); - return; - } - - a = lastNumber / 1000; - lastNumber -= a*1000; - b = lastNumber / 100; - lastNumber -= b*100; - c = lastNumber / 10; - lastNumber -= c*10; - d = lastNumber; - - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.jpg" - , a, b, c, d ); -} - -/* -==================== -R_LevelShot - -levelshots are specialized 128*128 thumbnails for -the menu system, sampled down from full screen distorted images -==================== -*/ -void R_LevelShot( void ) { - char checkname[MAX_OSPATH]; - byte *buffer; - byte *source, *allsource; - byte *src, *dst; - size_t offset = 0; - int padlen; - int x, y; - int r, g, b; - float xScale, yScale; - int xx, yy; - - Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName); - - allsource = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &padlen); - source = allsource + offset; - - buffer = ri.Hunk_AllocateTempMemory(128 * 128*3 + 18); - Com_Memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = 128; - buffer[14] = 128; - buffer[16] = 24; // pixel size - - // resample from source - xScale = glConfig.vidWidth / 512.0f; - yScale = glConfig.vidHeight / 384.0f; - for ( y = 0 ; y < 128 ; y++ ) { - for ( x = 0 ; x < 128 ; x++ ) { - r = g = b = 0; - for ( yy = 0 ; yy < 3 ; yy++ ) { - for ( xx = 0 ; xx < 4 ; xx++ ) { - src = source + (3 * glConfig.vidWidth + padlen) * (int)((y*3 + yy) * yScale) + - 3 * (int) ((x*4 + xx) * xScale); - r += src[0]; - g += src[1]; - b += src[2]; - } - } - dst = buffer + 18 + 3 * ( y * 128 + x ); - dst[0] = b / 12; - dst[1] = g / 12; - dst[2] = r / 12; - } - } - - // gamma correct - if ( glConfig.deviceSupportsGamma ) { - R_GammaCorrect( buffer + 18, 128 * 128 * 3 ); - } - - ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 ); - - ri.Hunk_FreeTempMemory(buffer); - ri.Hunk_FreeTempMemory(allsource); - - ri.Printf( PRINT_ALL, "Wrote %s\n", checkname ); -} - -/* -================== -R_ScreenShot_f - -screenshot -screenshot [silent] -screenshot [levelshot] -screenshot [filename] - -Doesn't print the pacifier message if there is a second arg -================== -*/ -void R_ScreenShot_f (void) { - char checkname[MAX_OSPATH]; - static int lastNumber = -1; - qboolean silent; - - if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) { - R_LevelShot(); - return; - } - - if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) { - silent = qtrue; - } else { - silent = qfalse; - } - - if ( ri.Cmd_Argc() == 2 && !silent ) { - // explicit filename - Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv( 1 ) ); - } else { - // scan for a free filename - - // if we have saved a previous screenshot, don't scan - // again, because recording demo avis can involve - // thousands of shots - if ( lastNumber == -1 ) { - lastNumber = 0; - } - // scan for a free number - for ( ; lastNumber <= 9999 ; lastNumber++ ) { - R_ScreenshotFilename( lastNumber, checkname ); - - if (!ri.FS_FileExists( checkname )) - { - break; // file doesn't exist - } - } - - if ( lastNumber >= 9999 ) { - ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n"); - return; - } - - lastNumber++; - } - - R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qfalse ); - - if ( !silent ) { - ri.Printf (PRINT_ALL, "Wrote %s\n", checkname); - } -} - -void R_ScreenShotJPEG_f (void) { - char checkname[MAX_OSPATH]; - static int lastNumber = -1; - qboolean silent; - - if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) { - R_LevelShot(); - return; - } - - if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) { - silent = qtrue; - } else { - silent = qfalse; - } - - if ( ri.Cmd_Argc() == 2 && !silent ) { - // explicit filename - Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.jpg", ri.Cmd_Argv( 1 ) ); - } else { - // scan for a free filename - - // if we have saved a previous screenshot, don't scan - // again, because recording demo avis can involve - // thousands of shots - if ( lastNumber == -1 ) { - lastNumber = 0; - } - // scan for a free number - for ( ; lastNumber <= 9999 ; lastNumber++ ) { - R_ScreenshotFilenameJPEG( lastNumber, checkname ); - - if (!ri.FS_FileExists( checkname )) - { - break; // file doesn't exist - } - } - - if ( lastNumber == 10000 ) { - ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n"); - return; - } - - lastNumber++; - } - - R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qtrue ); - - if ( !silent ) { - ri.Printf (PRINT_ALL, "Wrote %s\n", checkname); - } -} - -//============================================================================ - -/* -================== -RB_TakeVideoFrameCmd -================== -*/ -const void *RB_TakeVideoFrameCmd( const void *data ) -{ - const videoFrameCommand_t *cmd; - byte *cBuf; - size_t memcount, linelen; - int padwidth, avipadwidth, padlen, avipadlen; - GLint packAlign; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - cmd = (const videoFrameCommand_t *)data; - - qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); - - linelen = cmd->width * 3; - - // Alignment stuff for glReadPixels - padwidth = PAD(linelen, packAlign); - padlen = padwidth - linelen; - // AVI line padding - avipadwidth = PAD(linelen, AVI_LINE_PADDING); - avipadlen = avipadwidth - linelen; - - cBuf = PADP(cmd->captureBuffer, packAlign); - - qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB, - GL_UNSIGNED_BYTE, cBuf); - - memcount = padwidth * cmd->height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(cBuf, memcount); - - if(cmd->motionJpeg) - { - memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height, - r_aviMotionJpegQuality->integer, - cmd->width, cmd->height, cBuf, padlen); - ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount); - } - else - { - byte *lineend, *memend; - byte *srcptr, *destptr; - - srcptr = cBuf; - destptr = cmd->encodeBuffer; - memend = srcptr + memcount; - - // swap R and B and remove line paddings - while(srcptr < memend) - { - lineend = srcptr + linelen; - while(srcptr < lineend) - { - *destptr++ = srcptr[2]; - *destptr++ = srcptr[1]; - *destptr++ = srcptr[0]; - srcptr += 3; - } - - Com_Memset(destptr, '\0', avipadlen); - destptr += avipadlen; - - srcptr += padlen; - } - - ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, avipadwidth * cmd->height); - } - - return (const void *)(cmd + 1); -} - -//============================================================================ - -/* -** GL_SetDefaultState -*/ -void GL_SetDefaultState( void ) -{ - qglClearDepth( 1.0f ); - - qglCullFace(GL_FRONT); - - qglColor4f (1,1,1,1); - - // initialize downstream texture unit if we're running - // in a multitexture environment - if ( qglActiveTextureARB ) { - GL_SelectTexture( 1 ); - GL_TextureMode( r_textureMode->string ); - GL_TexEnv( GL_MODULATE ); - qglDisable( GL_TEXTURE_2D ); - GL_SelectTexture( 0 ); - } - - qglEnable(GL_TEXTURE_2D); - GL_TextureMode( r_textureMode->string ); - GL_TexEnv( GL_MODULATE ); - - //qglShadeModel( GL_SMOOTH ); - qglDepthFunc( GL_LEQUAL ); - - // - // make sure our GL state vector is set correctly - // - glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE; - - glState.vertexAttribsState = 0; - glState.vertexAttribPointersSet = 0; - glState.currentProgram = 0; - qglUseProgramObjectARB(0); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - glState.currentVBO = NULL; - glState.currentIBO = NULL; - - qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - qglDepthMask( GL_TRUE ); - qglDisable( GL_DEPTH_TEST ); - qglEnable( GL_SCISSOR_TEST ); - qglDisable( GL_CULL_FACE ); - qglDisable( GL_BLEND ); - - if (glRefConfig.seamlessCubeMap) - qglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); -} - -/* -================ -R_PrintLongString - -Workaround for ri.Printf's 1024 characters buffer limit. -================ -*/ -void R_PrintLongString(const char *string) { - char buffer[1024]; - const char *p; - int size = strlen(string); - - p = string; - while(size > 0) - { - Q_strncpyz(buffer, p, sizeof (buffer) ); - ri.Printf( PRINT_ALL, "%s", buffer ); - p += 1023; - size -= 1023; - } -} - -/* -================ -GfxInfo_f -================ -*/ -void GfxInfo_f( void ) -{ - const char *enablestrings[] = - { - "disabled", - "enabled" - }; - const char *fsstrings[] = - { - "windowed", - "fullscreen" - }; - - ri.Printf( PRINT_ALL, "\nGL_VENDOR: %s\n", glConfig.vendor_string ); - ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string ); - ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string ); - ri.Printf( PRINT_ALL, "GL_EXTENSIONS: " ); - R_PrintLongString( glConfig.extensions_string ); - ri.Printf( PRINT_ALL, "\n" ); - ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize ); - ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.numTextureUnits ); - ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits ); - ri.Printf( PRINT_ALL, "MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] ); - if ( glConfig.displayFrequency ) - { - ri.Printf( PRINT_ALL, "%d\n", glConfig.displayFrequency ); - } - else - { - ri.Printf( PRINT_ALL, "N/A\n" ); - } - if ( glConfig.deviceSupportsGamma ) - { - ri.Printf( PRINT_ALL, "GAMMA: hardware w/ %d overbright bits\n", tr.overbrightBits ); - } - else - { - ri.Printf( PRINT_ALL, "GAMMA: software w/ %d overbright bits\n", tr.overbrightBits ); - } - - ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string ); - ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer ); - ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer ); - ri.Printf( PRINT_ALL, "multitexture: %s\n", enablestrings[qglActiveTextureARB != 0] ); - ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] ); - ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] ); - ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] ); - if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) - { - ri.Printf( PRINT_ALL, "HACK: using vertex lightmap approximation\n" ); - } - if ( glConfig.hardwareType == GLHW_RAGEPRO ) - { - ri.Printf( PRINT_ALL, "HACK: ragePro approximations\n" ); - } - if ( glConfig.hardwareType == GLHW_RIVA128 ) - { - ri.Printf( PRINT_ALL, "HACK: riva128 approximations\n" ); - } - if ( r_finish->integer ) { - ri.Printf( PRINT_ALL, "Forcing glFinish\n" ); - } -} - -/* -================ -GfxMemInfo_f -================ -*/ -void GfxMemInfo_f( void ) -{ - switch (glRefConfig.memInfo) - { - case MI_NONE: - { - ri.Printf(PRINT_ALL, "No extension found for GPU memory info.\n"); - } - break; - case MI_NVX: - { - int value; - - qglGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &value); - ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX: %ikb\n", value); - - qglGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &value); - ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: %ikb\n", value); - - qglGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &value); - ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX: %ikb\n", value); - - qglGetIntegerv(GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX, &value); - ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_EVICTION_COUNT_NVX: %i\n", value); - - qglGetIntegerv(GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX, &value); - ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_EVICTED_MEMORY_NVX: %ikb\n", value); - } - break; - case MI_ATI: - { - // GL_ATI_meminfo - int value[4]; - - qglGetIntegerv(GL_VBO_FREE_MEMORY_ATI, &value[0]); - ri.Printf(PRINT_ALL, "VBO_FREE_MEMORY_ATI: %ikb total %ikb largest aux: %ikb total %ikb largest\n", value[0], value[1], value[2], value[3]); - - qglGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, &value[0]); - ri.Printf(PRINT_ALL, "TEXTURE_FREE_MEMORY_ATI: %ikb total %ikb largest aux: %ikb total %ikb largest\n", value[0], value[1], value[2], value[3]); - - qglGetIntegerv(GL_RENDERBUFFER_FREE_MEMORY_ATI, &value[0]); - ri.Printf(PRINT_ALL, "RENDERBUFFER_FREE_MEMORY_ATI: %ikb total %ikb largest aux: %ikb total %ikb largest\n", value[0], value[1], value[2], value[3]); - } - break; - } -} - -/* -=============== -R_Register -=============== -*/ -void R_Register( void ) -{ - #ifdef USE_RENDERER_DLOPEN - com_altivec = ri.Cvar_Get("com_altivec", "1", CVAR_ARCHIVE); - #endif - - // - // latched and archived variables - // - r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH); - - r_ext_draw_range_elements = ri.Cvar_Get( "r_ext_draw_range_elements", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_multi_draw_arrays = ri.Cvar_Get( "r_ext_multi_draw_arrays", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_framebuffer_object = ri.Cvar_Get( "r_ext_framebuffer_object", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_texture_float = ri.Cvar_Get( "r_ext_texture_float", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_arb_half_float_pixel = ri.Cvar_Get( "r_arb_half_float_pixel", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_framebuffer_multisample = ri.Cvar_Get( "r_ext_framebuffer_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_arb_seamless_cube_map = ri.Cvar_Get( "r_arb_seamless_cube_map", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_arb_vertex_type_2_10_10_10_rev = ri.Cvar_Get( "r_arb_vertex_type_2_10_10_10_rev", "1", CVAR_ARCHIVE | CVAR_LATCH); - - r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", - "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "2", CVAR_ARCHIVE | CVAR_LATCH ); - - r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH ); - ri.Cvar_CheckRange( r_picmip, 0, 16, qtrue ); - r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH ); - r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH ); - ri.Cvar_CheckRange( r_ext_multisample, 0, 4, qtrue ); - r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_mode = ri.Cvar_Get( "r_mode", "-2", CVAR_ARCHIVE | CVAR_LATCH ); - r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE ); - r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH ); - r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH ); - r_customPixelAspect = ri.Cvar_Get( "r_customPixelAspect", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_simpleMipMaps = ri.Cvar_Get( "r_simpleMipMaps", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0); - r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH); - r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH); - ri.Cvar_CheckRange(r_greyscale, 0, 1, qfalse); - - r_softOverbright = ri.Cvar_Get( "r_softOverbright", "1", CVAR_ARCHIVE | CVAR_LATCH ); - - r_hdr = ri.Cvar_Get( "r_hdr", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_floatLightmap = ri.Cvar_Get( "r_floatLightmap", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_postProcess = ri.Cvar_Get( "r_postProcess", "1", CVAR_ARCHIVE ); - - r_toneMap = ri.Cvar_Get( "r_toneMap", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_forceToneMap = ri.Cvar_Get( "r_forceToneMap", "0", CVAR_CHEAT ); - r_forceToneMapMin = ri.Cvar_Get( "r_forceToneMapMin", "-8.0", CVAR_CHEAT ); - r_forceToneMapAvg = ri.Cvar_Get( "r_forceToneMapAvg", "-2.0", CVAR_CHEAT ); - r_forceToneMapMax = ri.Cvar_Get( "r_forceToneMapMax", "0.0", CVAR_CHEAT ); - - r_autoExposure = ri.Cvar_Get( "r_autoExposure", "1", CVAR_ARCHIVE ); - r_forceAutoExposure = ri.Cvar_Get( "r_forceAutoExposure", "0", CVAR_CHEAT ); - r_forceAutoExposureMin = ri.Cvar_Get( "r_forceAutoExposureMin", "-2.0", CVAR_CHEAT ); - r_forceAutoExposureMax = ri.Cvar_Get( "r_forceAutoExposureMax", "2.0", CVAR_CHEAT ); - - r_cameraExposure = ri.Cvar_Get( "r_cameraExposure", "0", CVAR_CHEAT ); - - r_srgb = ri.Cvar_Get( "r_srgb", "0", CVAR_ARCHIVE | CVAR_LATCH ); - - r_depthPrepass = ri.Cvar_Get( "r_depthPrepass", "1", CVAR_ARCHIVE ); - r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE ); - - r_normalMapping = ri.Cvar_Get( "r_normalMapping", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_specularMapping = ri.Cvar_Get( "r_specularMapping", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_deluxeMapping = ri.Cvar_Get( "r_deluxeMapping", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_parallaxMapping = ri.Cvar_Get( "r_parallaxMapping", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_cubeMapping = ri.Cvar_Get( "r_cubeMapping", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_deluxeSpecular = ri.Cvar_Get( "r_deluxeSpecular", "0.3", CVAR_ARCHIVE | CVAR_LATCH ); - r_specularIsMetallic = ri.Cvar_Get( "r_specularIsMetallic", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_baseSpecular = ri.Cvar_Get( "r_baseSpecular", "0.04", CVAR_ARCHIVE | CVAR_LATCH ); - r_baseGloss = ri.Cvar_Get( "r_baseGloss", "0.3", CVAR_ARCHIVE | CVAR_LATCH ); - r_dlightMode = ri.Cvar_Get( "r_dlightMode", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_pshadowDist = ri.Cvar_Get( "r_pshadowDist", "128", CVAR_ARCHIVE ); - r_recalcMD3Normals = ri.Cvar_Get( "r_recalcMD3Normals", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_mergeLightmaps = ri.Cvar_Get( "r_mergeLightmaps", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_imageUpsample = ri.Cvar_Get( "r_imageUpsample", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_imageUpsampleMaxSize = ri.Cvar_Get( "r_imageUpsampleMaxSize", "1024", CVAR_ARCHIVE | CVAR_LATCH ); - r_imageUpsampleType = ri.Cvar_Get( "r_imageUpsampleType", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_genNormalMaps = ri.Cvar_Get( "r_genNormalMaps", "0", CVAR_ARCHIVE | CVAR_LATCH ); - - r_forceSun = ri.Cvar_Get( "r_forceSun", "0", CVAR_CHEAT ); - r_forceSunMapLightScale = ri.Cvar_Get( "r_forceSunMapLightScale", "1.0", CVAR_CHEAT ); - r_forceSunLightScale = ri.Cvar_Get( "r_forceSunLightScale", "1.0", CVAR_CHEAT ); - r_forceSunAmbientScale = ri.Cvar_Get( "r_forceSunAmbientScale", "0.5", CVAR_CHEAT ); - r_drawSunRays = ri.Cvar_Get( "r_drawSunRays", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_sunlightMode = ri.Cvar_Get( "r_sunlightMode", "1", CVAR_ARCHIVE | CVAR_LATCH ); - - r_sunShadows = ri.Cvar_Get( "r_sunShadows", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_shadowFilter = ri.Cvar_Get( "r_shadowFilter", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_shadowMapSize = ri.Cvar_Get( "r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH ); - r_shadowCascadeZNear = ri.Cvar_Get( "r_shadowCascadeZNear", "4", CVAR_ARCHIVE | CVAR_LATCH ); - r_shadowCascadeZFar = ri.Cvar_Get( "r_shadowCascadeZFar", "3072", CVAR_ARCHIVE | CVAR_LATCH ); - r_shadowCascadeZBias = ri.Cvar_Get( "r_shadowCascadeZBias", "-320", CVAR_ARCHIVE | CVAR_LATCH ); - r_ignoreDstAlpha = ri.Cvar_Get( "r_ignoreDstAlpha", "1", CVAR_ARCHIVE | CVAR_LATCH ); - - // - // temporary latched variables that can only change over a restart - // - r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT ); - r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH ); - r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH ); - r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH ); - - // - // archived variables that can change at any time - // - r_lodCurveError = ri.Cvar_Get( "r_lodCurveError", "250", CVAR_ARCHIVE|CVAR_CHEAT ); - r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE ); - r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE ); - r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT ); - ri.Cvar_CheckRange( r_znear, 0.001f, 200, qfalse ); - r_zproj = ri.Cvar_Get( "r_zproj", "64", CVAR_ARCHIVE ); - r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", CVAR_ARCHIVE ); - r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE ); - r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE ); - r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE ); - r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE ); - r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE ); - r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE ); - r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE); - r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE ); - r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0", - CVAR_ARCHIVE | CVAR_LATCH ); - r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE ); - r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE ); - - r_railWidth = ri.Cvar_Get( "r_railWidth", "16", CVAR_ARCHIVE ); - r_railCoreWidth = ri.Cvar_Get( "r_railCoreWidth", "6", CVAR_ARCHIVE ); - r_railSegmentLength = ri.Cvar_Get( "r_railSegmentLength", "32", CVAR_ARCHIVE ); - - r_ambientScale = ri.Cvar_Get( "r_ambientScale", "0.6", CVAR_CHEAT ); - r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT ); - - r_anaglyphMode = ri.Cvar_Get("r_anaglyphMode", "0", CVAR_ARCHIVE); - r_mergeMultidraws = ri.Cvar_Get("r_mergeMultidraws", "1", CVAR_ARCHIVE); - r_mergeLeafSurfaces = ri.Cvar_Get("r_mergeLeafSurfaces", "1", CVAR_ARCHIVE); - - // - // temporary variables that can change at any time - // - r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_TEMP ); - - r_debugLight = ri.Cvar_Get( "r_debuglight", "0", CVAR_TEMP ); - r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT ); - r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 ); - r_saveFontData = ri.Cvar_Get( "r_saveFontData", "0", 0 ); - - r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT ); - r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT ); - r_lightmap = ri.Cvar_Get ("r_lightmap", "0", 0 ); - r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_CHEAT ); - - r_flareSize = ri.Cvar_Get ("r_flareSize", "40", CVAR_CHEAT); - r_flareFade = ri.Cvar_Get ("r_flareFade", "7", CVAR_CHEAT); - r_flareCoeff = ri.Cvar_Get ("r_flareCoeff", FLARE_STDCOEFF, CVAR_CHEAT); - - r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT); - - r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); - r_lodscale = ri.Cvar_Get( "r_lodscale", "5", CVAR_CHEAT ); - r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT); - r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT ); - r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT ); - r_nocull = ri.Cvar_Get ("r_nocull", "0", CVAR_CHEAT); - r_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT); - r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT); - r_speeds = ri.Cvar_Get ("r_speeds", "0", CVAR_CHEAT); - r_verbose = ri.Cvar_Get( "r_verbose", "0", CVAR_CHEAT ); - r_logFile = ri.Cvar_Get( "r_logFile", "0", CVAR_CHEAT ); - r_debugSurface = ri.Cvar_Get ("r_debugSurface", "0", CVAR_CHEAT); - r_nobind = ri.Cvar_Get ("r_nobind", "0", CVAR_CHEAT); - r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT); - r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT); - r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT); - r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT); - r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT ); - r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT ); - r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT ); - r_lockpvs = ri.Cvar_Get ("r_lockpvs", "0", CVAR_CHEAT); - r_noportals = ri.Cvar_Get ("r_noportals", "0", CVAR_CHEAT); - r_shadows = ri.Cvar_Get( "cg_shadows", "1", 0 ); - - r_marksOnTriangleMeshes = ri.Cvar_Get("r_marksOnTriangleMeshes", "0", CVAR_ARCHIVE); - - r_aviMotionJpegQuality = ri.Cvar_Get("r_aviMotionJpegQuality", "90", CVAR_ARCHIVE); - r_screenshotJpegQuality = ri.Cvar_Get("r_screenshotJpegQuality", "90", CVAR_ARCHIVE); - - r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0); - r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0); - - // make sure all the commands added here are also - // removed in R_Shutdown - ri.Cmd_AddCommand( "imagelist", R_ImageList_f ); - ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f ); - ri.Cmd_AddCommand( "skinlist", R_SkinList_f ); - ri.Cmd_AddCommand( "modellist", R_Modellist_f ); - ri.Cmd_AddCommand( "modelist", R_ModeList_f ); - ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f ); - ri.Cmd_AddCommand( "screenshotJPEG", R_ScreenShotJPEG_f ); - ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f ); - ri.Cmd_AddCommand( "minimize", GLimp_Minimize ); - ri.Cmd_AddCommand( "gfxmeminfo", GfxMemInfo_f ); -} - -void R_InitQueries(void) -{ - if (!glRefConfig.occlusionQuery) - return; - - if (r_drawSunRays->integer) - qglGenQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); -} - -void R_ShutDownQueries(void) -{ - if (!glRefConfig.occlusionQuery) - return; - - if (r_drawSunRays->integer) - qglDeleteQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); -} - -/* -=============== -R_Init -=============== -*/ -void R_Init( void ) { - int err; - int i; - byte *ptr; - - ri.Printf( PRINT_ALL, "----- R_Init -----\n" ); - - // clear all our internal state - Com_Memset( &tr, 0, sizeof( tr ) ); - Com_Memset( &backEnd, 0, sizeof( backEnd ) ); - Com_Memset( &tess, 0, sizeof( tess ) ); - - if(sizeof(glconfig_t) != 11332) - ri.Error( ERR_FATAL, "Mod ABI incompatible: sizeof(glconfig_t) == %u != 11332", (unsigned int) sizeof(glconfig_t)); - -// Swap_Init(); - - if ( (intptr_t)tess.xyz & 15 ) { - ri.Printf( PRINT_WARNING, "tess.xyz not 16 byte aligned\n" ); - } - //Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) ); - - // - // init function tables - // - for ( i = 0; i < FUNCTABLE_SIZE; i++ ) - { - tr.sinTable[i] = sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) ); - tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f; - tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE; - tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i]; - - if ( i < FUNCTABLE_SIZE / 2 ) - { - if ( i < FUNCTABLE_SIZE / 4 ) - { - tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 ); - } - else - { - tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4]; - } - } - else - { - tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2]; - } - } - - R_InitFogTable(); - - R_NoiseInit(); - - R_Register(); - - max_polys = r_maxpolys->integer; - if (max_polys < MAX_POLYS) - max_polys = MAX_POLYS; - - max_polyverts = r_maxpolyverts->integer; - if (max_polyverts < MAX_POLYVERTS) - max_polyverts = MAX_POLYVERTS; - - ptr = ri.Hunk_Alloc( sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); - backEndData = (backEndData_t *) ptr; - backEndData->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData )); - backEndData->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys); - R_InitNextFrame(); - - InitOpenGL(); - - R_InitImages(); - - if (glRefConfig.framebufferObject) - FBO_Init(); - - GLSL_InitGPUShaders(); - - R_InitVBOs(); - - R_InitShaders(); - - R_InitSkins(); - - R_ModelInit(); - - R_InitFreeType(); - - R_InitQueries(); - - - err = qglGetError(); - if ( err != GL_NO_ERROR ) - ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err); - - // print info - GfxInfo_f(); - ri.Printf( PRINT_ALL, "----- finished R_Init -----\n" ); -} - -/* -=============== -RE_Shutdown -=============== -*/ -void RE_Shutdown( qboolean destroyWindow ) { - - ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow ); - - ri.Cmd_RemoveCommand ("modellist"); - ri.Cmd_RemoveCommand ("screenshotJPEG"); - ri.Cmd_RemoveCommand ("screenshot"); - ri.Cmd_RemoveCommand ("imagelist"); - ri.Cmd_RemoveCommand ("shaderlist"); - ri.Cmd_RemoveCommand ("skinlist"); - ri.Cmd_RemoveCommand ("gfxinfo"); - ri.Cmd_RemoveCommand("minimize"); - ri.Cmd_RemoveCommand( "modelist" ); - ri.Cmd_RemoveCommand( "shaderstate" ); - ri.Cmd_RemoveCommand( "gfxmeminfo" ); - - - if ( tr.registered ) { - R_IssuePendingRenderCommands(); - R_ShutDownQueries(); - if (glRefConfig.framebufferObject) - FBO_Shutdown(); - R_DeleteTextures(); - R_ShutdownVBOs(); - GLSL_ShutdownGPUShaders(); - } - - R_DoneFreeType(); - - // shut down platform specific OpenGL stuff - if ( destroyWindow ) { - GLimp_Shutdown(); - - Com_Memset( &glConfig, 0, sizeof( glConfig ) ); - Com_Memset( &glState, 0, sizeof( glState ) ); - } - - tr.registered = qfalse; -} - - -/* -============= -RE_EndRegistration - -Touch all images to make sure they are resident -============= -*/ -void RE_EndRegistration( void ) { - R_IssuePendingRenderCommands(); - if (!ri.Sys_LowPhysicalMemory()) { - RB_ShowImages(); - } -} - - -/* -@@@@@@@@@@@@@@@@@@@@@ -GetRefAPI - -@@@@@@@@@@@@@@@@@@@@@ -*/ -#ifdef USE_RENDERER_DLOPEN -Q_EXPORT refexport_t* QDECL GetRefAPI ( int apiVersion, refimport_t *rimp ) { -#else -refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { -#endif - - static refexport_t re; - - ri = *rimp; - - Com_Memset( &re, 0, sizeof( re ) ); - - if ( apiVersion != REF_API_VERSION ) { - ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n", - REF_API_VERSION, apiVersion ); - return NULL; - } - - // the RE_ functions are Renderer Entry points - - re.Shutdown = RE_Shutdown; - - re.BeginRegistration = RE_BeginRegistration; - re.RegisterModel = RE_RegisterModel; - re.RegisterSkin = RE_RegisterSkin; - re.RegisterShader = RE_RegisterShader; - re.RegisterShaderNoMip = RE_RegisterShaderNoMip; - re.LoadWorld = RE_LoadWorldMap; - re.SetWorldVisData = RE_SetWorldVisData; - re.EndRegistration = RE_EndRegistration; - - re.BeginFrame = RE_BeginFrame; - re.EndFrame = RE_EndFrame; - - re.MarkFragments = R_MarkFragments; - re.LerpTag = R_LerpTag; - re.ModelBounds = R_ModelBounds; - - re.ClearScene = RE_ClearScene; - re.AddRefEntityToScene = RE_AddRefEntityToScene; - re.AddPolyToScene = RE_AddPolyToScene; - re.LFX_ParticleEffect = NULL; - re.LightForPoint = R_LightForPoint; - re.AddLightToScene = RE_AddLightToScene; - re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene; - re.RenderScene = RE_RenderScene; - - re.SetColor = RE_SetColor; - re.DrawStretchPic = RE_StretchPic; - re.DrawStretchRaw = RE_StretchRaw; - re.UploadCinematic = RE_UploadCinematic; - - re.RegisterFont = RE_RegisterFont; - re.RemapShader = R_RemapShader; - re.GetEntityToken = R_GetEntityToken; - re.inPVS = R_inPVS; - - re.TakeVideoFrame = RE_TakeVideoFrame; - - return &re; -} diff --git a/code/renderergl2/tr_light.c b/code/renderergl2/tr_light.c deleted file mode 100644 index 3d1d1f241a..0000000000 --- a/code/renderergl2/tr_light.c +++ /dev/null @@ -1,488 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_light.c - -#include "tr_local.h" - -#define DLIGHT_AT_RADIUS 16 -// at the edge of a dlight's influence, this amount of light will be added - -#define DLIGHT_MINIMUM_RADIUS 16 -// never calculate a range less than this to prevent huge light numbers - - -/* -=============== -R_TransformDlights - -Transforms the origins of an array of dlights. -Used by both the front end (for DlightBmodel) and -the back end (before doing the lighting calculation) -=============== -*/ -void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) { - int i; - vec3_t temp; - - for ( i = 0 ; i < count ; i++, dl++ ) { - VectorSubtract( dl->origin, or->origin, temp ); - dl->transformed[0] = DotProduct( temp, or->axis[0] ); - dl->transformed[1] = DotProduct( temp, or->axis[1] ); - dl->transformed[2] = DotProduct( temp, or->axis[2] ); - } -} - -/* -============= -R_DlightBmodel - -Determine which dynamic lights may effect this bmodel -============= -*/ -void R_DlightBmodel( bmodel_t *bmodel ) { - int i, j; - dlight_t *dl; - int mask; - msurface_t *surf; - - // transform all the lights - R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or ); - - mask = 0; - for ( i=0 ; itransformed[j] - bmodel->bounds[1][j] > dl->radius ) { - break; - } - if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) { - break; - } - } - if ( j < 3 ) { - continue; - } - - // we need to check this light - mask |= 1 << i; - } - - tr.currentEntity->needDlights = (mask != 0); - - // set the dlight bits in all the surfaces - for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) { - surf = tr.world->surfaces + bmodel->firstSurface + i; - - switch(*surf->data) - { - case SF_FACE: - case SF_GRID: - case SF_TRIANGLES: - case SF_VBO_MESH: - ((srfBspSurface_t *)surf->data)->dlightBits = mask; - break; - - default: - break; - } - } -} - - -/* -============================================================================= - -LIGHT SAMPLING - -============================================================================= -*/ - -extern cvar_t *r_ambientScale; -extern cvar_t *r_directedScale; -extern cvar_t *r_debugLight; - -/* -================= -R_SetupEntityLightingGrid - -================= -*/ -static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) { - vec3_t lightOrigin; - int pos[3]; - int i, j; - byte *gridData; - float frac[3]; - int gridStep[3]; - vec3_t direction; - float totalFactor; - - if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is - // sinking into the ground can still be lit, and so - // multi-part models can be lit identically - VectorCopy( ent->e.lightingOrigin, lightOrigin ); - } else { - VectorCopy( ent->e.origin, lightOrigin ); - } - - VectorSubtract( lightOrigin, world->lightGridOrigin, lightOrigin ); - for ( i = 0 ; i < 3 ; i++ ) { - float v; - - v = lightOrigin[i]*world->lightGridInverseSize[i]; - pos[i] = floor( v ); - frac[i] = v - pos[i]; - if ( pos[i] < 0 ) { - pos[i] = 0; - } else if ( pos[i] >= world->lightGridBounds[i] - 1 ) { - pos[i] = world->lightGridBounds[i] - 1; - } - } - - VectorClear( ent->ambientLight ); - VectorClear( ent->directedLight ); - VectorClear( direction ); - - assert( world->lightGridData ); // NULL with -nolight maps - - // trilerp the light value - gridStep[0] = 8; - gridStep[1] = 8 * world->lightGridBounds[0]; - gridStep[2] = 8 * world->lightGridBounds[0] * world->lightGridBounds[1]; - gridData = world->lightGridData + pos[0] * gridStep[0] - + pos[1] * gridStep[1] + pos[2] * gridStep[2]; - - totalFactor = 0; - for ( i = 0 ; i < 8 ; i++ ) { - float factor; - byte *data; - int lat, lng; - vec3_t normal; - qboolean ignore; - #if idppc - float d0, d1, d2, d3, d4, d5; - #endif - factor = 1.0; - data = gridData; - ignore = qfalse; - for ( j = 0 ; j < 3 ; j++ ) { - if ( i & (1<= world->lightGridBounds[j] - 1) - { - ignore = qtrue; // ignore values outside lightgrid - } - factor *= frac[j]; - data += gridStep[j]; - } else { - factor *= (1.0f - frac[j]); - } - } - - if ( ignore ) - continue; - - if (world->hdrLightGrid) - { - float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6; - if (!(hdrData[0]+hdrData[1]+hdrData[2]+hdrData[3]+hdrData[4]+hdrData[5]) ) { - continue; // ignore samples in walls - } - } - else - { - if (!(data[0]+data[1]+data[2]+data[3]+data[4]+data[5]) ) { - continue; // ignore samples in walls - } - } - totalFactor += factor; - #if idppc - d0 = data[0]; d1 = data[1]; d2 = data[2]; - d3 = data[3]; d4 = data[4]; d5 = data[5]; - - ent->ambientLight[0] += factor * d0; - ent->ambientLight[1] += factor * d1; - ent->ambientLight[2] += factor * d2; - - ent->directedLight[0] += factor * d3; - ent->directedLight[1] += factor * d4; - ent->directedLight[2] += factor * d5; - #else - if (world->hdrLightGrid) - { - // FIXME: this is hideous - float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6; - - ent->ambientLight[0] += factor * hdrData[0]; - ent->ambientLight[1] += factor * hdrData[1]; - ent->ambientLight[2] += factor * hdrData[2]; - - ent->directedLight[0] += factor * hdrData[3]; - ent->directedLight[1] += factor * hdrData[4]; - ent->directedLight[2] += factor * hdrData[5]; - } - else - { - ent->ambientLight[0] += factor * data[0]; - ent->ambientLight[1] += factor * data[1]; - ent->ambientLight[2] += factor * data[2]; - - ent->directedLight[0] += factor * data[3]; - ent->directedLight[1] += factor * data[4]; - ent->directedLight[2] += factor * data[5]; - } - #endif - lat = data[7]; - lng = data[6]; - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - VectorMA( direction, factor, normal, direction ); - } - - if ( totalFactor > 0 && totalFactor < 0.99 ) { - totalFactor = 1.0f / totalFactor; - VectorScale( ent->ambientLight, totalFactor, ent->ambientLight ); - VectorScale( ent->directedLight, totalFactor, ent->directedLight ); - } - - VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight ); - VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight ); - - VectorNormalize2( direction, ent->lightDir ); -} - - -/* -=============== -LogLight -=============== -*/ -static void LogLight( trRefEntity_t *ent ) { - int max1, max2; - - if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) { - return; - } - - max1 = ent->ambientLight[0]; - if ( ent->ambientLight[1] > max1 ) { - max1 = ent->ambientLight[1]; - } else if ( ent->ambientLight[2] > max1 ) { - max1 = ent->ambientLight[2]; - } - - max2 = ent->directedLight[0]; - if ( ent->directedLight[1] > max2 ) { - max2 = ent->directedLight[1]; - } else if ( ent->directedLight[2] > max2 ) { - max2 = ent->directedLight[2]; - } - - ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 ); -} - -/* -================= -R_SetupEntityLighting - -Calculates all the lighting values that will be used -by the Calc_* functions -================= -*/ -void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { - int i; - dlight_t *dl; - float power; - vec3_t dir; - float d; - vec3_t lightDir; - vec3_t lightOrigin; - - // lighting calculations - if ( ent->lightingCalculated ) { - return; - } - ent->lightingCalculated = qtrue; - - // - // trace a sample point down to find ambient light - // - if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is - // sinking into the ground can still be lit, and so - // multi-part models can be lit identically - VectorCopy( ent->e.lightingOrigin, lightOrigin ); - } else { - VectorCopy( ent->e.origin, lightOrigin ); - } - - // if NOWORLDMODEL, only use dynamic lights (menu system, etc) - if ( !(refdef->rdflags & RDF_NOWORLDMODEL ) - && tr.world->lightGridData ) { - R_SetupEntityLightingGrid( ent, tr.world ); - } else { - ent->ambientLight[0] = ent->ambientLight[1] = - ent->ambientLight[2] = tr.identityLight * 150; - ent->directedLight[0] = ent->directedLight[1] = - ent->directedLight[2] = tr.identityLight * 150; - VectorCopy( tr.sunDirection, ent->lightDir ); - } - - // bonus items and view weapons have a fixed minimum add - if ( !r_hdr->integer /* ent->e.renderfx & RF_MINLIGHT */ ) { - // give everything a minimum light add - ent->ambientLight[0] += tr.identityLight * 32; - ent->ambientLight[1] += tr.identityLight * 32; - ent->ambientLight[2] += tr.identityLight * 32; - } - - // - // modify the light by dynamic lights - // - d = VectorLength( ent->directedLight ); - VectorScale( ent->lightDir, d, lightDir ); - - for ( i = 0 ; i < refdef->num_dlights ; i++ ) { - dl = &refdef->dlights[i]; - VectorSubtract( dl->origin, lightOrigin, dir ); - d = VectorNormalize( dir ); - - power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius ); - if ( d < DLIGHT_MINIMUM_RADIUS ) { - d = DLIGHT_MINIMUM_RADIUS; - } - d = power / ( d * d ); - - VectorMA( ent->directedLight, d, dl->color, ent->directedLight ); - VectorMA( lightDir, d, dir, lightDir ); - } - - // clamp ambient - if ( !r_hdr->integer ) - { - for ( i = 0 ; i < 3 ; i++ ) { - if ( ent->ambientLight[i] > tr.identityLightByte ) { - ent->ambientLight[i] = tr.identityLightByte; - } - } - } - - if ( r_debugLight->integer ) { - LogLight( ent ); - } - - // save out the byte packet version - ((byte *)&ent->ambientLightInt)[0] = ri.ftol(ent->ambientLight[0]); - ((byte *)&ent->ambientLightInt)[1] = ri.ftol(ent->ambientLight[1]); - ((byte *)&ent->ambientLightInt)[2] = ri.ftol(ent->ambientLight[2]); - ((byte *)&ent->ambientLightInt)[3] = 0xff; - - // transform the direction to local space - VectorNormalize( lightDir ); - ent->modelLightDir[0] = DotProduct( lightDir, ent->e.axis[0] ); - ent->modelLightDir[1] = DotProduct( lightDir, ent->e.axis[1] ); - ent->modelLightDir[2] = DotProduct( lightDir, ent->e.axis[2] ); - - VectorCopy(lightDir, ent->lightDir); -} - -/* -================= -R_LightForPoint -================= -*/ -int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) -{ - trRefEntity_t ent; - - if ( tr.world->lightGridData == NULL ) - return qfalse; - - Com_Memset(&ent, 0, sizeof(ent)); - VectorCopy( point, ent.e.origin ); - R_SetupEntityLightingGrid( &ent, tr.world ); - VectorCopy(ent.ambientLight, ambientLight); - VectorCopy(ent.directedLight, directedLight); - VectorCopy(ent.lightDir, lightDir); - - return qtrue; -} - - -int R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *world ) -{ - trRefEntity_t ent; - - if ( world->lightGridData == NULL ) - return qfalse; - - Com_Memset(&ent, 0, sizeof(ent)); - VectorCopy( point, ent.e.origin ); - R_SetupEntityLightingGrid( &ent, world ); - - if (DotProduct(ent.lightDir, normal) > 0.2f) - VectorCopy(ent.lightDir, lightDir); - else - VectorCopy(normal, lightDir); - - return qtrue; -} - - -int R_CubemapForPoint( vec3_t point ) -{ - int cubemapIndex = -1; - - if (r_cubeMapping->integer && tr.numCubemaps) - { - int i; - vec_t shortest = (float)WORLD_SIZE * (float)WORLD_SIZE; - - for (i = 0; i < tr.numCubemaps; i++) - { - vec3_t diff; - vec_t length; - - VectorSubtract(point, tr.cubemapOrigins[i], diff); - length = DotProduct(diff, diff); - - if (shortest > length) - { - shortest = length; - cubemapIndex = i; - } - } - } - - return cubemapIndex + 1; -} diff --git a/code/renderergl2/tr_local.h b/code/renderergl2/tr_local.h deleted file mode 100644 index 0fbabd20fc..0000000000 --- a/code/renderergl2/tr_local.h +++ /dev/null @@ -1,2499 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - - -#ifndef TR_LOCAL_H -#define TR_LOCAL_H - -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "../renderercommon/tr_public.h" -#include "../renderercommon/tr_common.h" -#include "tr_extratypes.h" -#include "tr_extramath.h" -#include "tr_fbo.h" -#include "tr_postprocess.h" -#include "../renderercommon/iqm.h" -#include "../renderercommon/qgl.h" - -#define GL_INDEX_TYPE GL_UNSIGNED_INT -typedef unsigned int glIndex_t; - -#define BUFFER_OFFSET(i) ((char *)NULL + (i)) - -// 14 bits -// can't be increased without changing bit packing for drawsurfs -// see QSORT_SHADERNUM_SHIFT -#define SHADERNUM_BITS 14 -#define MAX_SHADERS (1<or.origin in local coordinates - float modelMatrix[16]; - float transformMatrix[16]; -} orientationr_t; - -typedef enum -{ - VBO_USAGE_STATIC, - VBO_USAGE_DYNAMIC -} vboUsage_t; - -typedef struct VBO_s -{ - char name[MAX_QPATH]; - - uint32_t vertexesVBO; - int vertexesSize; // amount of memory data allocated for all vertices in bytes - uint32_t ofs_xyz; - uint32_t ofs_normal; - uint32_t ofs_st; - uint32_t ofs_lightmap; - uint32_t ofs_vertexcolor; - uint32_t ofs_lightdir; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t ofs_tangent; -#endif - uint32_t stride_xyz; - uint32_t stride_normal; - uint32_t stride_st; - uint32_t stride_lightmap; - uint32_t stride_vertexcolor; - uint32_t stride_lightdir; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t stride_tangent; -#endif - uint32_t size_xyz; - uint32_t size_normal; - - int attribs; -} VBO_t; - -typedef struct IBO_s -{ - char name[MAX_QPATH]; - - uint32_t indexesVBO; - int indexesSize; // amount of memory data allocated for all triangles in bytes -// uint32_t ofsIndexes; -} IBO_t; - -//=============================================================================== - -typedef enum { - SS_BAD, - SS_PORTAL, // mirrors, portals, viewscreens - SS_ENVIRONMENT, // sky box - SS_OPAQUE, // opaque - - SS_DECAL, // scorch marks, etc. - SS_SEE_THROUGH, // ladders, grates, grills that may have small blended edges - // in addition to alpha test - SS_BANNER, - - SS_FOG, - - SS_UNDERWATER, // for items that should be drawn in front of the water plane - - SS_BLEND0, // regular transparency and filters - SS_BLEND1, // generally only used for additive type effects - SS_BLEND2, - SS_BLEND3, - - SS_BLEND6, - SS_STENCIL_SHADOW, - SS_ALMOST_NEAREST, // gun smoke puffs - - SS_NEAREST // blood blobs -} shaderSort_t; - - -#define MAX_SHADER_STAGES 8 - -typedef enum { - GF_NONE, - - GF_SIN, - GF_SQUARE, - GF_TRIANGLE, - GF_SAWTOOTH, - GF_INVERSE_SAWTOOTH, - - GF_NOISE - -} genFunc_t; - - -typedef enum { - DEFORM_NONE, - DEFORM_WAVE, - DEFORM_NORMALS, - DEFORM_BULGE, - DEFORM_MOVE, - DEFORM_PROJECTION_SHADOW, - DEFORM_AUTOSPRITE, - DEFORM_AUTOSPRITE2, - DEFORM_TEXT0, - DEFORM_TEXT1, - DEFORM_TEXT2, - DEFORM_TEXT3, - DEFORM_TEXT4, - DEFORM_TEXT5, - DEFORM_TEXT6, - DEFORM_TEXT7 -} deform_t; - -// deformVertexes types that can be handled by the GPU -typedef enum -{ - // do not edit: same as genFunc_t - - DGEN_NONE, - DGEN_WAVE_SIN, - DGEN_WAVE_SQUARE, - DGEN_WAVE_TRIANGLE, - DGEN_WAVE_SAWTOOTH, - DGEN_WAVE_INVERSE_SAWTOOTH, - DGEN_WAVE_NOISE, - - // do not edit until this line - - DGEN_BULGE, - DGEN_MOVE -} deformGen_t; - -typedef enum { - AGEN_IDENTITY, - AGEN_SKIP, - AGEN_ENTITY, - AGEN_ONE_MINUS_ENTITY, - AGEN_VERTEX, - AGEN_ONE_MINUS_VERTEX, - AGEN_LIGHTING_SPECULAR, - AGEN_WAVEFORM, - AGEN_PORTAL, - AGEN_CONST, -} alphaGen_t; - -typedef enum { - CGEN_BAD, - CGEN_IDENTITY_LIGHTING, // tr.identityLight - CGEN_IDENTITY, // always (1,1,1,1) - CGEN_ENTITY, // grabbed from entity's modulate field - CGEN_ONE_MINUS_ENTITY, // grabbed from 1 - entity.modulate - CGEN_EXACT_VERTEX, // tess.vertexColors - CGEN_VERTEX, // tess.vertexColors * tr.identityLight - CGEN_EXACT_VERTEX_LIT, // like CGEN_EXACT_VERTEX but takes a light direction from the lightgrid - CGEN_VERTEX_LIT, // like CGEN_VERTEX but takes a light direction from the lightgrid - CGEN_ONE_MINUS_VERTEX, - CGEN_WAVEFORM, // programmatically generated - CGEN_LIGHTING_DIFFUSE, - CGEN_FOG, // standard fog - CGEN_CONST // fixed color -} colorGen_t; - -typedef enum { - TCGEN_BAD, - TCGEN_IDENTITY, // clear to 0,0 - TCGEN_LIGHTMAP, - TCGEN_TEXTURE, - TCGEN_ENVIRONMENT_MAPPED, - TCGEN_FOG, - TCGEN_VECTOR // S and T from world coordinates -} texCoordGen_t; - -typedef enum { - ACFF_NONE, - ACFF_MODULATE_RGB, - ACFF_MODULATE_RGBA, - ACFF_MODULATE_ALPHA -} acff_t; - -typedef struct { - genFunc_t func; - - float base; - float amplitude; - float phase; - float frequency; -} waveForm_t; - -#define TR_MAX_TEXMODS 4 - -typedef enum { - TMOD_NONE, - TMOD_TRANSFORM, - TMOD_TURBULENT, - TMOD_SCROLL, - TMOD_SCALE, - TMOD_STRETCH, - TMOD_ROTATE, - TMOD_ENTITY_TRANSLATE -} texMod_t; - -#define MAX_SHADER_DEFORMS 3 -typedef struct { - deform_t deformation; // vertex coordinate modification type - - vec3_t moveVector; - waveForm_t deformationWave; - float deformationSpread; - - float bulgeWidth; - float bulgeHeight; - float bulgeSpeed; -} deformStage_t; - - -typedef struct { - texMod_t type; - - // used for TMOD_TURBULENT and TMOD_STRETCH - waveForm_t wave; - - // used for TMOD_TRANSFORM - float matrix[2][2]; // s' = s * m[0][0] + t * m[1][0] + trans[0] - float translate[2]; // t' = s * m[0][1] + t * m[0][1] + trans[1] - - // used for TMOD_SCALE - float scale[2]; // s *= scale[0] - // t *= scale[1] - - // used for TMOD_SCROLL - float scroll[2]; // s' = s + scroll[0] * time - // t' = t + scroll[1] * time - - // + = clockwise - // - = counterclockwise - float rotateSpeed; - -} texModInfo_t; - - -#define MAX_IMAGE_ANIMATIONS 8 - -typedef struct { - image_t *image[MAX_IMAGE_ANIMATIONS]; - int numImageAnimations; - float imageAnimationSpeed; - - texCoordGen_t tcGen; - vec3_t tcGenVectors[2]; - - int numTexMods; - texModInfo_t *texMods; - - int videoMapHandle; - qboolean isLightmap; - qboolean isVideoMap; -} textureBundle_t; - -enum -{ - TB_COLORMAP = 0, - TB_DIFFUSEMAP = 0, - TB_LIGHTMAP = 1, - TB_LEVELSMAP = 1, - TB_SHADOWMAP3 = 1, - TB_NORMALMAP = 2, - TB_DELUXEMAP = 3, - TB_SHADOWMAP2 = 3, - TB_SPECULARMAP = 4, - TB_SHADOWMAP = 5, - TB_CUBEMAP = 6, - NUM_TEXTURE_BUNDLES = 7 -}; - -typedef enum -{ - // material shader stage types - ST_COLORMAP = 0, // vanilla Q3A style shader treatening - ST_DIFFUSEMAP = 0, // treat color and diffusemap the same - ST_NORMALMAP, - ST_NORMALPARALLAXMAP, - ST_SPECULARMAP, - ST_GLSL -} stageType_t; - -typedef struct { - qboolean active; - - textureBundle_t bundle[NUM_TEXTURE_BUNDLES]; - - waveForm_t rgbWave; - colorGen_t rgbGen; - - waveForm_t alphaWave; - alphaGen_t alphaGen; - - byte constantColor[4]; // for CGEN_CONST and AGEN_CONST - - unsigned stateBits; // GLS_xxxx mask - - acff_t adjustColorsForFog; - - qboolean isDetail; - - stageType_t type; - struct shaderProgram_s *glslShaderGroup; - int glslShaderIndex; - vec2_t materialInfo; -} shaderStage_t; - -struct shaderCommands_s; - -typedef enum { - CT_FRONT_SIDED, - CT_BACK_SIDED, - CT_TWO_SIDED -} cullType_t; - -typedef enum { - FP_NONE, // surface is translucent and will just be adjusted properly - FP_EQUAL, // surface is opaque but possibly alpha tested - FP_LE // surface is trnaslucent, but still needs a fog pass (fog surface) -} fogPass_t; - -typedef struct { - float cloudHeight; - image_t *outerbox[6], *innerbox[6]; -} skyParms_t; - -typedef struct { - vec3_t color; - float depthForOpaque; -} fogParms_t; - - -typedef struct shader_s { - char name[MAX_QPATH]; // game path, including extension - int lightmapIndex; // for a shader to match, both name and lightmapIndex must match - - int index; // this shader == tr.shaders[index] - int sortedIndex; // this shader == tr.sortedShaders[sortedIndex] - - float sort; // lower numbered shaders draw before higher numbered - - qboolean defaultShader; // we want to return index 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - - qboolean explicitlyDefined; // found in a .shader file - - int surfaceFlags; // if explicitlyDefined, this will have SURF_* flags - int contentFlags; - - qboolean entityMergable; // merge across entites optimizable (smoke, blood) - - qboolean isSky; - skyParms_t sky; - fogParms_t fogParms; - - float portalRange; // distance to fog out at - qboolean isPortal; - - int multitextureEnv; // 0, GL_MODULATE, GL_ADD (FIXME: put in stage) - - cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED - qboolean polygonOffset; // set for decals and other items that must be offset - qboolean noMipMaps; // for console fonts, 2D elements, etc. - qboolean noPicMip; // for images that must always be full resolution - - fogPass_t fogPass; // draw a blended pass, possibly with depth test equals - - int vertexAttribs; // not all shaders will need all data to be gathered - - int numDeforms; - deformStage_t deforms[MAX_SHADER_DEFORMS]; - - int numUnfoggedPasses; - shaderStage_t *stages[MAX_SHADER_STAGES]; - - void (*optimalStageIteratorFunc)( void ); - - float clampTime; // time this shader is clamped to - float timeOffset; // current time offset for this shader - - struct shader_s *remappedShader; // current shader this one is remapped too - - struct shader_s *next; -} shader_t; - -static ID_INLINE qboolean ShaderRequiresCPUDeforms(const shader_t * shader) -{ - if(shader->numDeforms) - { - const deformStage_t *ds = &shader->deforms[0]; - - if (shader->numDeforms > 1) - return qtrue; - - switch (ds->deformation) - { - case DEFORM_WAVE: - case DEFORM_BULGE: - return qfalse; - - default: - return qtrue; - } - } - - return qfalse; -} - -enum -{ - ATTR_INDEX_POSITION = 0, - ATTR_INDEX_TEXCOORD0 = 1, - ATTR_INDEX_TEXCOORD1 = 2, - ATTR_INDEX_TANGENT = 3, - ATTR_INDEX_NORMAL = 4, - ATTR_INDEX_COLOR = 5, - ATTR_INDEX_PAINTCOLOR = 6, - ATTR_INDEX_LIGHTDIRECTION = 7, - ATTR_INDEX_BONE_INDEXES = 8, - ATTR_INDEX_BONE_WEIGHTS = 9, - - // GPU vertex animations - ATTR_INDEX_POSITION2 = 10, - ATTR_INDEX_TANGENT2 = 11, - ATTR_INDEX_NORMAL2 = 12 -}; - -enum -{ - ATTR_POSITION = 0x0001, - ATTR_TEXCOORD = 0x0002, - ATTR_LIGHTCOORD = 0x0004, - ATTR_TANGENT = 0x0008, - ATTR_NORMAL = 0x0010, - ATTR_COLOR = 0x0020, - ATTR_PAINTCOLOR = 0x0040, - ATTR_LIGHTDIRECTION = 0x0080, - ATTR_BONE_INDEXES = 0x0100, - ATTR_BONE_WEIGHTS = 0x0200, - - // for .md3 interpolation - ATTR_POSITION2 = 0x0400, - ATTR_TANGENT2 = 0x0800, - ATTR_NORMAL2 = 0x1000, - - ATTR_DEFAULT = ATTR_POSITION, - ATTR_BITS = ATTR_POSITION | - ATTR_TEXCOORD | - ATTR_LIGHTCOORD | - ATTR_TANGENT | - ATTR_NORMAL | - ATTR_COLOR | - ATTR_PAINTCOLOR | - ATTR_LIGHTDIRECTION | - ATTR_BONE_INDEXES | - ATTR_BONE_WEIGHTS | - ATTR_POSITION2 | - ATTR_TANGENT2 | - ATTR_NORMAL2 -}; - -enum -{ - GENERICDEF_USE_DEFORM_VERTEXES = 0x0001, - GENERICDEF_USE_TCGEN_AND_TCMOD = 0x0002, - GENERICDEF_USE_VERTEX_ANIMATION = 0x0004, - GENERICDEF_USE_FOG = 0x0008, - GENERICDEF_USE_RGBAGEN = 0x0010, - GENERICDEF_USE_LIGHTMAP = 0x0020, - GENERICDEF_ALL = 0x003F, - GENERICDEF_COUNT = 0x0040, -}; - -enum -{ - FOGDEF_USE_DEFORM_VERTEXES = 0x0001, - FOGDEF_USE_VERTEX_ANIMATION = 0x0002, - FOGDEF_ALL = 0x0003, - FOGDEF_COUNT = 0x0004, -}; - -enum -{ - DLIGHTDEF_USE_DEFORM_VERTEXES = 0x0001, - DLIGHTDEF_ALL = 0x0001, - DLIGHTDEF_COUNT = 0x0002, -}; - -enum -{ - LIGHTDEF_USE_LIGHTMAP = 0x0001, - LIGHTDEF_USE_LIGHT_VECTOR = 0x0002, - LIGHTDEF_USE_LIGHT_VERTEX = 0x0003, - LIGHTDEF_LIGHTTYPE_MASK = 0x0003, - LIGHTDEF_ENTITY = 0x0004, - LIGHTDEF_USE_TCGEN_AND_TCMOD = 0x0008, - LIGHTDEF_USE_PARALLAXMAP = 0x0010, - LIGHTDEF_USE_SHADOWMAP = 0x0020, - LIGHTDEF_ALL = 0x003F, - LIGHTDEF_COUNT = 0x0040 -}; - -enum -{ - GLSL_INT, - GLSL_FLOAT, - GLSL_FLOAT5, - GLSL_VEC2, - GLSL_VEC3, - GLSL_VEC4, - GLSL_MAT16 -}; - -typedef enum -{ - UNIFORM_DIFFUSEMAP = 0, - UNIFORM_LIGHTMAP, - UNIFORM_NORMALMAP, - UNIFORM_DELUXEMAP, - UNIFORM_SPECULARMAP, - - UNIFORM_TEXTUREMAP, - UNIFORM_LEVELSMAP, - UNIFORM_CUBEMAP, - - UNIFORM_SCREENIMAGEMAP, - UNIFORM_SCREENDEPTHMAP, - - UNIFORM_SHADOWMAP, - UNIFORM_SHADOWMAP2, - UNIFORM_SHADOWMAP3, - - UNIFORM_SHADOWMVP, - UNIFORM_SHADOWMVP2, - UNIFORM_SHADOWMVP3, - - UNIFORM_ENABLETEXTURES, - - UNIFORM_DIFFUSETEXMATRIX, - UNIFORM_DIFFUSETEXOFFTURB, - UNIFORM_TEXTURE1ENV, - - UNIFORM_TCGEN0, - UNIFORM_TCGEN0VECTOR0, - UNIFORM_TCGEN0VECTOR1, - - UNIFORM_DEFORMGEN, - UNIFORM_DEFORMPARAMS, - - UNIFORM_COLORGEN, - UNIFORM_ALPHAGEN, - UNIFORM_COLOR, - UNIFORM_BASECOLOR, - UNIFORM_VERTCOLOR, - - UNIFORM_DLIGHTINFO, - UNIFORM_LIGHTFORWARD, - UNIFORM_LIGHTUP, - UNIFORM_LIGHTRIGHT, - UNIFORM_LIGHTORIGIN, - UNIFORM_MODELLIGHTDIR, - UNIFORM_LIGHTRADIUS, - UNIFORM_AMBIENTLIGHT, - UNIFORM_DIRECTEDLIGHT, - - UNIFORM_PORTALRANGE, - - UNIFORM_FOGDISTANCE, - UNIFORM_FOGDEPTH, - UNIFORM_FOGEYET, - UNIFORM_FOGCOLORMASK, - - UNIFORM_MODELMATRIX, - UNIFORM_MODELVIEWPROJECTIONMATRIX, - - UNIFORM_TIME, - UNIFORM_VERTEXLERP, - UNIFORM_MATERIALINFO, - - UNIFORM_VIEWINFO, // znear, zfar, width/2, height/2 - UNIFORM_VIEWORIGIN, - UNIFORM_LOCALVIEWORIGIN, - UNIFORM_VIEWFORWARD, - UNIFORM_VIEWLEFT, - UNIFORM_VIEWUP, - - UNIFORM_INVTEXRES, - UNIFORM_AUTOEXPOSUREMINMAX, - UNIFORM_TONEMINAVGMAXLINEAR, - - UNIFORM_PRIMARYLIGHTORIGIN, - UNIFORM_PRIMARYLIGHTCOLOR, - UNIFORM_PRIMARYLIGHTAMBIENT, - UNIFORM_PRIMARYLIGHTRADIUS, - - UNIFORM_COUNT -} uniform_t; - -// shaderProgram_t represents a pair of one -// GLSL vertex and one GLSL fragment shader -typedef struct shaderProgram_s -{ - char name[MAX_QPATH]; - - GLhandleARB program; - GLhandleARB vertexShader; - GLhandleARB fragmentShader; - uint32_t attribs; // vertex array attributes - - // uniform parameters - GLint uniforms[UNIFORM_COUNT]; - short uniformBufferOffsets[UNIFORM_COUNT]; // max 32767/64=511 uniforms - char *uniformBuffer; -} shaderProgram_t; - -// trRefdef_t holds everything that comes in refdef_t, -// as well as the locally generated scene information -typedef struct { - int x, y, width, height; - float fov_x, fov_y; - vec3_t vieworg; - vec3_t viewaxis[3]; // transformation matrix - - stereoFrame_t stereoFrame; - - int time; // time in milliseconds for shader effects and other time dependent rendering issues - int rdflags; // RDF_NOWORLDMODEL, etc - - // 1 bits will prevent the associated area from rendering at all - byte areamask[MAX_MAP_AREA_BYTES]; - qboolean areamaskModified; // qtrue if areamask changed since last scene - - float floatTime; // tr.refdef.time / 1000.0 - - float blurFactor; - - // text messages for deform text shaders - char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; - - int num_entities; - trRefEntity_t *entities; - - int num_dlights; - struct dlight_s *dlights; - - int numPolys; - struct srfPoly_s *polys; - - int numDrawSurfs; - struct drawSurf_s *drawSurfs; - - unsigned int dlightMask; - int num_pshadows; - struct pshadow_s *pshadows; - - float sunShadowMvp[3][16]; - float sunDir[4]; - float sunCol[4]; - float sunAmbCol[4]; - float colorScale; - - float autoExposureMinMax[2]; - float toneMinAvgMaxLinear[3]; -} trRefdef_t; - - -//================================================================================= - -// skins allow models to be retextured without modifying the model file -typedef struct { - char name[MAX_QPATH]; - shader_t *shader; -} skinSurface_t; - -typedef struct skin_s { - char name[MAX_QPATH]; // game path, including extension - int numSurfaces; - skinSurface_t *surfaces[MD3_MAX_SURFACES]; -} skin_t; - - -typedef struct { - int originalBrushNumber; - vec3_t bounds[2]; - - unsigned colorInt; // in packed byte format - float tcScale; // texture coordinate vector scales - fogParms_t parms; - - // for clipping distance in fog when outside - qboolean hasSurface; - float surface[4]; -} fog_t; - -typedef enum { - VPF_NONE = 0x00, - VPF_NOVIEWMODEL = 0x01, - VPF_SHADOWMAP = 0x02, - VPF_DEPTHSHADOW = 0x04, - VPF_DEPTHCLAMP = 0x08, - VPF_ORTHOGRAPHIC = 0x10, - VPF_USESUNLIGHT = 0x20, - VPF_FARPLANEFRUSTUM = 0x40, - VPF_NOCUBEMAPS = 0x80 -} viewParmFlags_t; - -typedef struct { - orientationr_t or; - orientationr_t world; - vec3_t pvsOrigin; // may be different than or.origin for portals - qboolean isPortal; // true if this view is through a portal - qboolean isMirror; // the portal is a mirror, invert the face culling - viewParmFlags_t flags; - int frameSceneNum; // copied from tr.frameSceneNum - int frameCount; // copied from tr.frameCount - cplane_t portalPlane; // clip anything behind this if mirroring - int viewportX, viewportY, viewportWidth, viewportHeight; - FBO_t *targetFbo; - int targetFboLayer; - int targetFboCubemapIndex; - float fovX, fovY; - float projectionMatrix[16]; - cplane_t frustum[5]; - vec3_t visBounds[2]; - float zFar; - float zNear; - stereoFrame_t stereoFrame; -} viewParms_t; - - -/* -============================================================================== - -SURFACES - -============================================================================== -*/ -typedef byte color4ub_t[4]; - -// any changes in surfaceType must be mirrored in rb_surfaceTable[] -typedef enum { - SF_BAD, - SF_SKIP, // ignore - SF_FACE, - SF_GRID, - SF_TRIANGLES, - SF_POLY, - SF_MDV, - SF_MDR, - SF_IQM, - SF_FLARE, - SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity - SF_DISPLAY_LIST, - SF_VBO_MESH, - SF_VBO_MDVMESH, - - SF_NUM_SURFACE_TYPES, - SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int ) -} surfaceType_t; - -typedef struct drawSurf_s { - unsigned int sort; // bit combination for fast compares - int cubemapIndex; - surfaceType_t *surface; // any of surface*_t -} drawSurf_t; - -#define MAX_FACE_POINTS 64 - -#define MAX_PATCH_SIZE 32 // max dimensions of a patch mesh in map file -#define MAX_GRID_SIZE 65 // max dimensions of a grid mesh in memory - -// when cgame directly specifies a polygon, it becomes a srfPoly_t -// as soon as it is called -typedef struct srfPoly_s { - surfaceType_t surfaceType; - qhandle_t hShader; - int fogIndex; - int numVerts; - polyVert_t *verts; -} srfPoly_t; - -typedef struct srfDisplayList_s { - surfaceType_t surfaceType; - int listNum; -} srfDisplayList_t; - - -typedef struct srfFlare_s { - surfaceType_t surfaceType; - vec3_t origin; - vec3_t normal; - vec3_t color; -} srfFlare_t; - -typedef struct -{ - vec3_t xyz; - vec2_t st; - vec2_t lightmap; - vec3_t normal; -#ifdef USE_VERT_TANGENT_SPACE - vec4_t tangent; -#endif - vec3_t lightdir; - vec4_t vertexColors; - -#if DEBUG_OPTIMIZEVERTICES - unsigned int id; -#endif -} srfVert_t; - -#ifdef USE_VERT_TANGENT_SPACE -#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0}, {0, 0, 0, 0}} -#else -#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0, 0}} -#endif - -// srfBspSurface_t covers SF_GRID, SF_TRIANGLES, SF_POLY, and SF_VBO_MESH -typedef struct srfBspSurface_s -{ - surfaceType_t surfaceType; - - // dynamic lighting information - int dlightBits; - int pshadowBits; - - // culling information - vec3_t cullBounds[2]; - vec3_t cullOrigin; - float cullRadius; - cplane_t cullPlane; - - // indexes - int numIndexes; - glIndex_t *indexes; - - // vertexes - int numVerts; - srfVert_t *verts; - - // BSP VBO offsets - int firstVert; - int firstIndex; - glIndex_t minIndex; - glIndex_t maxIndex; - - // static render data - VBO_t *vbo; - IBO_t *ibo; - - // SF_GRID specific variables after here - - // lod information, which may be different - // than the culling information to allow for - // groups of curves that LOD as a unit - vec3_t lodOrigin; - float lodRadius; - int lodFixed; - int lodStitched; - - // vertexes - int width, height; - float *widthLodError; - float *heightLodError; -} srfBspSurface_t; - -// inter-quake-model -typedef struct { - int num_vertexes; - int num_triangles; - int num_frames; - int num_surfaces; - int num_joints; - int num_poses; - struct srfIQModel_s *surfaces; - - float *positions; - float *texcoords; - float *normals; - float *tangents; - byte *blendIndexes; - union { - float *f; - byte *b; - } blendWeights; - byte *colors; - int *triangles; - - // depending upon the exporter, blend indices and weights might be int/float - // as opposed to the recommended byte/byte, for example Noesis exports - // int/float whereas the official IQM tool exports byte/byte - byte blendWeightsType; // IQM_UBYTE or IQM_FLOAT - - int *jointParents; - float *jointMats; - float *poseMats; - float *bounds; - char *names; -} iqmData_t; - -// inter-quake-model surface -typedef struct srfIQModel_s { - surfaceType_t surfaceType; - char name[MAX_QPATH]; - shader_t *shader; - iqmData_t *data; - int first_vertex, num_vertexes; - int first_triangle, num_triangles; -} srfIQModel_t; - -typedef struct srfVBOMDVMesh_s -{ - surfaceType_t surfaceType; - - struct mdvModel_s *mdvModel; - struct mdvSurface_s *mdvSurface; - - // backEnd stats - int numIndexes; - int numVerts; - glIndex_t minIndex; - glIndex_t maxIndex; - - // static render data - VBO_t *vbo; - IBO_t *ibo; -} srfVBOMDVMesh_t; - -extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *); - -/* -============================================================================== - -SHADOWS - -============================================================================== -*/ - -typedef struct pshadow_s -{ - float sort; - - int numEntities; - int entityNums[8]; - vec3_t entityOrigins[8]; - float entityRadiuses[8]; - - float viewRadius; - vec3_t viewOrigin; - - vec3_t lightViewAxis[3]; - vec3_t lightOrigin; - float lightRadius; - cplane_t cullPlane; -} pshadow_t; - - -/* -============================================================================== - -BRUSH MODELS - -============================================================================== -*/ - - -// -// in memory representation -// - -#define SIDE_FRONT 0 -#define SIDE_BACK 1 -#define SIDE_ON 2 - -#define CULLINFO_NONE 0 -#define CULLINFO_BOX 1 -#define CULLINFO_SPHERE 2 -#define CULLINFO_PLANE 4 - -typedef struct cullinfo_s { - int type; - vec3_t bounds[2]; - vec3_t localOrigin; - float radius; - cplane_t plane; -} cullinfo_t; - -typedef struct msurface_s { - //int viewCount; // if == tr.viewCount, already added - struct shader_s *shader; - int fogIndex; - int cubemapIndex; - cullinfo_t cullinfo; - - surfaceType_t *data; // any of srf*_t -} msurface_t; - - -#define CONTENTS_NODE -1 -typedef struct mnode_s { - // common with leaf and node - int contents; // -1 for nodes, to differentiate from leafs - int visCounts[MAX_VISCOUNTS]; // node needs to be traversed if current - vec3_t mins, maxs; // for bounding box culling - struct mnode_s *parent; - - // node specific - cplane_t *plane; - struct mnode_s *children[2]; - - // leaf specific - int cluster; - int area; - - int firstmarksurface; - int nummarksurfaces; -} mnode_t; - -typedef struct { - vec3_t bounds[2]; // for culling - int firstSurface; - int numSurfaces; -} bmodel_t; - -typedef struct { - char name[MAX_QPATH]; // ie: maps/tim_dm2.bsp - char baseName[MAX_QPATH]; // ie: tim_dm2 - - int dataSize; - - int numShaders; - dshader_t *shaders; - - int numBModels; - bmodel_t *bmodels; - - int numplanes; - cplane_t *planes; - - int numnodes; // includes leafs - int numDecisionNodes; - mnode_t *nodes; - - int numWorldSurfaces; - - int numsurfaces; - msurface_t *surfaces; - int *surfacesViewCount; - int *surfacesDlightBits; - int *surfacesPshadowBits; - - int numMergedSurfaces; - msurface_t *mergedSurfaces; - int *mergedSurfacesViewCount; - int *mergedSurfacesDlightBits; - int *mergedSurfacesPshadowBits; - - int nummarksurfaces; - int *marksurfaces; - int *viewSurfaces; - - int numfogs; - fog_t *fogs; - - vec3_t lightGridOrigin; - vec3_t lightGridSize; - vec3_t lightGridInverseSize; - int lightGridBounds[3]; - byte *lightGridData; - float *hdrLightGrid; - - - int numClusters; - int clusterBytes; - const byte *vis; // may be passed in by CM_LoadMap to save space - - byte *novis; // clusterBytes of 0xff - - char *entityString; - char *entityParsePoint; -} world_t; - - -/* -============================================================================== -MDV MODELS - meta format for vertex animation models like .md2, .md3, .mdc -============================================================================== -*/ -typedef struct -{ - float bounds[2][3]; - float localOrigin[3]; - float radius; -} mdvFrame_t; - -typedef struct -{ - float origin[3]; - float axis[3][3]; -} mdvTag_t; - -typedef struct -{ - char name[MAX_QPATH]; // tag name -} mdvTagName_t; - -typedef struct -{ - vec3_t xyz; - vec3_t normal; -#ifdef USE_VERT_TANGENT_SPACE - vec3_t tangent; - vec3_t bitangent; -#endif -} mdvVertex_t; - -typedef struct -{ - float st[2]; -} mdvSt_t; - -typedef struct mdvSurface_s -{ - surfaceType_t surfaceType; - - char name[MAX_QPATH]; // polyset name - - int numShaderIndexes; - int *shaderIndexes; - - int numVerts; - mdvVertex_t *verts; - mdvSt_t *st; - - int numIndexes; - glIndex_t *indexes; - - struct mdvModel_s *model; -} mdvSurface_t; - -typedef struct mdvModel_s -{ - int numFrames; - mdvFrame_t *frames; - - int numTags; - mdvTag_t *tags; - mdvTagName_t *tagNames; - - int numSurfaces; - mdvSurface_t *surfaces; - - int numVBOSurfaces; - srfVBOMDVMesh_t *vboSurfaces; - - int numSkins; -} mdvModel_t; - - -//====================================================================== - -typedef enum { - MOD_BAD, - MOD_BRUSH, - MOD_MESH, - MOD_MDR, - MOD_IQM -} modtype_t; - -typedef struct model_s { - char name[MAX_QPATH]; - modtype_t type; - int index; // model = tr.models[model->index] - - int dataSize; // just for listing purposes - bmodel_t *bmodel; // only if type == MOD_BRUSH - mdvModel_t *mdv[MD3_MAX_LODS]; // only if type == MOD_MESH - void *modelData; // only if type == (MOD_MDR | MOD_IQM) - - int numLods; -} model_t; - - -#define MAX_MOD_KNOWN 1024 - -void R_ModelInit (void); -model_t *R_GetModelByHandle( qhandle_t hModel ); -int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, - float frac, const char *tagName ); -void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ); - -void R_Modellist_f (void); - -//==================================================== - -#define MAX_DRAWIMAGES 2048 -#define MAX_SKINS 1024 - - -#define MAX_DRAWSURFS 0x10000 -#define DRAWSURF_MASK (MAX_DRAWSURFS-1) - -/* - -the drawsurf sort data is packed into a single 32 bit value so it can be -compared quickly during the qsorting process - -the bits are allocated as follows: - -0 - 1 : dlightmap index -//2 : used to be clipped flag REMOVED - 03.21.00 rad -2 - 6 : fog index -11 - 20 : entity index -21 - 31 : sorted shader index - - TTimo - 1.32 -0-1 : dlightmap index -2-6 : fog index -7-16 : entity index -17-30 : sorted shader index - - SmileTheory - for pshadows -17-31 : sorted shader index -7-16 : entity index -2-6 : fog index -1 : pshadow flag -0 : dlight flag -*/ -#define QSORT_FOGNUM_SHIFT 2 -#define QSORT_REFENTITYNUM_SHIFT 7 -#define QSORT_SHADERNUM_SHIFT (QSORT_REFENTITYNUM_SHIFT+REFENTITYNUM_BITS) -#if (QSORT_SHADERNUM_SHIFT+SHADERNUM_BITS) > 32 - #error "Need to update sorting, too many bits." -#endif -#define QSORT_PSHADOW_SHIFT 1 - -extern int gl_filter_min, gl_filter_max; - -/* -** performanceCounters_t -*/ -typedef struct { - int c_sphere_cull_patch_in, c_sphere_cull_patch_clip, c_sphere_cull_patch_out; - int c_box_cull_patch_in, c_box_cull_patch_clip, c_box_cull_patch_out; - int c_sphere_cull_md3_in, c_sphere_cull_md3_clip, c_sphere_cull_md3_out; - int c_box_cull_md3_in, c_box_cull_md3_clip, c_box_cull_md3_out; - - int c_leafs; - int c_dlightSurfaces; - int c_dlightSurfacesCulled; -} frontEndCounters_t; - -#define FOG_TABLE_SIZE 256 -#define FUNCTABLE_SIZE 1024 -#define FUNCTABLE_SIZE2 10 -#define FUNCTABLE_MASK (FUNCTABLE_SIZE-1) - - -// the renderer front end should never modify glstate_t -typedef struct { - int currenttextures[NUM_TEXTURE_BUNDLES]; - int currenttmu; - qboolean finishCalled; - int texEnv[2]; - int faceCulling; - unsigned long glStateBits; - uint32_t vertexAttribsState; - uint32_t vertexAttribPointersSet; - uint32_t vertexAttribsNewFrame; - uint32_t vertexAttribsOldFrame; - float vertexAttribsInterpolation; - qboolean vertexAnimation; - shaderProgram_t *currentProgram; - FBO_t *currentFBO; - VBO_t *currentVBO; - IBO_t *currentIBO; - mat4_t modelview; - mat4_t projection; - mat4_t modelviewProjection; -} glstate_t; - -typedef enum { - MI_NONE, - MI_NVX, - MI_ATI -} memInfo_t; - -typedef enum { - TCR_NONE = 0x0000, - TCR_LATC = 0x0001, - TCR_BPTC = 0x0002, -} textureCompressionRef_t; - -// We can't change glConfig_t without breaking DLL/vms compatibility, so -// store extensions we have here. -typedef struct { - qboolean drawRangeElements; - qboolean multiDrawArrays; - qboolean occlusionQuery; - - int glslMajorVersion; - int glslMinorVersion; - - memInfo_t memInfo; - - qboolean framebufferObject; - int maxRenderbufferSize; - int maxColorAttachments; - - qboolean textureNonPowerOfTwo; - qboolean textureFloat; - qboolean halfFloatPixel; - qboolean packedDepthStencil; - textureCompressionRef_t textureCompression; - - qboolean framebufferMultisample; - qboolean framebufferBlit; - - qboolean textureSrgb; - qboolean framebufferSrgb; - qboolean textureSrgbDecode; - - qboolean depthClamp; - qboolean seamlessCubeMap; - - GLenum packedNormalDataType; -} glRefConfig_t; - - -typedef struct { - int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes; - int c_surfBatches; - float c_overDraw; - - int c_vboVertexBuffers; - int c_vboIndexBuffers; - int c_vboVertexes; - int c_vboIndexes; - - int c_staticVboDraws; - int c_dynamicVboDraws; - - int c_multidraws; - int c_multidrawsMerged; - - int c_dlightVertexes; - int c_dlightIndexes; - - int c_flareAdds; - int c_flareTests; - int c_flareRenders; - - int c_glslShaderBinds; - int c_genericDraws; - int c_lightallDraws; - int c_fogDraws; - int c_dlightDraws; - - int msec; // total msec for backend run -} backEndCounters_t; - -// all state modified by the back end is seperated -// from the front end state -typedef struct { - trRefdef_t refdef; - viewParms_t viewParms; - orientationr_t or; - backEndCounters_t pc; - qboolean isHyperspace; - trRefEntity_t *currentEntity; - qboolean skyRenderedThisView; // flag for drawing sun - - qboolean projection2D; // if qtrue, drawstretchpic doesn't need to change modes - byte color2D[4]; - qboolean vertexes2D; // shader needs to be finished - trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering - - FBO_t *last2DFBO; - qboolean colorMask[4]; - qboolean framePostProcessed; - qboolean depthFill; -} backEndState_t; - -/* -** trGlobals_t -** -** Most renderer globals are defined here. -** backend functions should never modify any of these fields, -** but may read fields that aren't dynamically modified -** by the frontend. -*/ -typedef struct { - qboolean registered; // cleared at shutdown, set at beginRegistration - - int visIndex; - int visClusters[MAX_VISCOUNTS]; - int visCounts[MAX_VISCOUNTS]; // incremented every time a new vis cluster is entered - - int frameCount; // incremented every frame - int sceneCount; // incremented every scene - int viewCount; // incremented every view (twice a scene if portaled) - // and every R_MarkFragments call - - int frameSceneNum; // zeroed at RE_BeginFrame - - qboolean worldMapLoaded; - qboolean worldDeluxeMapping; - vec2_t autoExposureMinMax; - vec3_t toneMinAvgMaxLevel; - world_t *world; - - const byte *externalVisData; // from RE_SetWorldVisData, shared with CM_Load - - image_t *defaultImage; - image_t *scratchImage[32]; - image_t *fogImage; - image_t *dlightImage; // inverse-quare highlight for projective adding - image_t *flareImage; - image_t *whiteImage; // full of 0xff - image_t *identityLightImage; // full of tr.identityLightByte - - image_t *shadowCubemaps[MAX_DLIGHTS]; - - - image_t *renderImage; - image_t *sunRaysImage; - image_t *renderDepthImage; - image_t *pshadowMaps[MAX_DRAWN_PSHADOWS]; - image_t *textureScratchImage[2]; - image_t *quarterImage[2]; - image_t *calcLevelsImage; - image_t *targetLevelsImage; - image_t *fixedLevelsImage; - image_t *sunShadowDepthImage[3]; - image_t *screenShadowImage; - image_t *screenSsaoImage; - image_t *hdrDepthImage; - image_t *renderCubeImage; - - image_t *textureDepthImage; - - FBO_t *renderFbo; - FBO_t *msaaResolveFbo; - FBO_t *sunRaysFbo; - FBO_t *depthFbo; - FBO_t *pshadowFbos[MAX_DRAWN_PSHADOWS]; - FBO_t *textureScratchFbo[2]; - FBO_t *quarterFbo[2]; - FBO_t *calcLevelsFbo; - FBO_t *targetLevelsFbo; - FBO_t *sunShadowFbo[3]; - FBO_t *screenShadowFbo; - FBO_t *screenSsaoFbo; - FBO_t *hdrDepthFbo; - FBO_t *renderCubeFbo; - - shader_t *defaultShader; - shader_t *shadowShader; - shader_t *projectionShadowShader; - - shader_t *flareShader; - shader_t *sunShader; - shader_t *sunFlareShader; - - int numLightmaps; - int lightmapSize; - image_t **lightmaps; - image_t **deluxemaps; - - int fatLightmapSize; - int fatLightmapStep; - - int numCubemaps; - vec3_t *cubemapOrigins; - image_t **cubemaps; - - trRefEntity_t *currentEntity; - trRefEntity_t worldEntity; // point currentEntity at this when rendering world - int currentEntityNum; - int shiftedEntityNum; // currentEntityNum << QSORT_REFENTITYNUM_SHIFT - model_t *currentModel; - - // - // GPU shader programs - // - shaderProgram_t genericShader[GENERICDEF_COUNT]; - shaderProgram_t textureColorShader; - shaderProgram_t fogShader[FOGDEF_COUNT]; - shaderProgram_t dlightShader[DLIGHTDEF_COUNT]; - shaderProgram_t lightallShader[LIGHTDEF_COUNT]; - shaderProgram_t shadowmapShader; - shaderProgram_t pshadowShader; - shaderProgram_t down4xShader; - shaderProgram_t bokehShader; - shaderProgram_t tonemapShader; - shaderProgram_t calclevels4xShader[2]; - shaderProgram_t shadowmaskShader; - shaderProgram_t ssaoShader; - shaderProgram_t depthBlurShader[2]; - shaderProgram_t testcubeShader; - - - // ----------------------------------------- - - viewParms_t viewParms; - - float identityLight; // 1.0 / ( 1 << overbrightBits ) - int identityLightByte; // identityLight * 255 - int overbrightBits; // r_overbrightBits->integer, but set to 0 if no hw gamma - - orientationr_t or; // for current entity - - trRefdef_t refdef; - - int viewCluster; - - float mapLightScale; - float sunShadowScale; - - qboolean sunShadows; - vec3_t sunLight; // from the sky shader for this level - vec3_t sunDirection; - - frontEndCounters_t pc; - int frontEndMsec; // not in pc due to clearing issue - - // - // put large tables at the end, so most elements will be - // within the +/32K indexed range on risc processors - // - model_t *models[MAX_MOD_KNOWN]; - int numModels; - - int numImages; - image_t *images[MAX_DRAWIMAGES]; - - int numFBOs; - FBO_t *fbos[MAX_FBOS]; - - int numVBOs; - VBO_t *vbos[MAX_VBOS]; - - int numIBOs; - IBO_t *ibos[MAX_IBOS]; - - // shader indexes from other modules will be looked up in tr.shaders[] - // shader indexes from drawsurfs will be looked up in sortedShaders[] - // lower indexed sortedShaders must be rendered first (opaque surfaces before translucent) - int numShaders; - shader_t *shaders[MAX_SHADERS]; - shader_t *sortedShaders[MAX_SHADERS]; - - int numSkins; - skin_t *skins[MAX_SKINS]; - - GLuint sunFlareQuery[2]; - int sunFlareQueryIndex; - qboolean sunFlareQueryActive[2]; - - float sinTable[FUNCTABLE_SIZE]; - float squareTable[FUNCTABLE_SIZE]; - float triangleTable[FUNCTABLE_SIZE]; - float sawToothTable[FUNCTABLE_SIZE]; - float inverseSawToothTable[FUNCTABLE_SIZE]; - float fogTable[FOG_TABLE_SIZE]; -} trGlobals_t; - -extern backEndState_t backEnd; -extern trGlobals_t tr; -extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init -extern glRefConfig_t glRefConfig; - -// -// cvars -// -extern cvar_t *r_flareSize; -extern cvar_t *r_flareFade; -// coefficient for the flare intensity falloff function. -#define FLARE_STDCOEFF "150" -extern cvar_t *r_flareCoeff; - -extern cvar_t *r_railWidth; -extern cvar_t *r_railCoreWidth; -extern cvar_t *r_railSegmentLength; - -extern cvar_t *r_ignore; // used for debugging anything -extern cvar_t *r_verbose; // used for verbose debug spew - -extern cvar_t *r_znear; // near Z clip plane -extern cvar_t *r_zproj; // z distance of projection plane -extern cvar_t *r_stereoSeparation; // separation of cameras for stereo rendering - -extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement - -extern cvar_t *r_lodbias; // push/pull LOD transitions -extern cvar_t *r_lodscale; - -extern cvar_t *r_inGameVideo; // controls whether in game video should be draw -extern cvar_t *r_fastsky; // controls whether sky should be cleared or drawn -extern cvar_t *r_drawSun; // controls drawing of sun quad -extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled -extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity - -extern cvar_t *r_norefresh; // bypasses the ref rendering -extern cvar_t *r_drawentities; // disable/enable entity rendering -extern cvar_t *r_drawworld; // disable/enable world rendering -extern cvar_t *r_speeds; // various levels of information display -extern cvar_t *r_detailTextures; // enables/disables detail texturing stages -extern cvar_t *r_novis; // disable/enable usage of PVS -extern cvar_t *r_nocull; -extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back side test -extern cvar_t *r_nocurves; -extern cvar_t *r_showcluster; - -extern cvar_t *r_gamma; - -extern cvar_t *r_ext_draw_range_elements; -extern cvar_t *r_ext_multi_draw_arrays; -extern cvar_t *r_ext_framebuffer_object; -extern cvar_t *r_ext_texture_float; -extern cvar_t *r_arb_half_float_pixel; -extern cvar_t *r_ext_framebuffer_multisample; -extern cvar_t *r_arb_seamless_cube_map; -extern cvar_t *r_arb_vertex_type_2_10_10_10_rev; - -extern cvar_t *r_nobind; // turns off binding to appropriate textures -extern cvar_t *r_singleShader; // make most world faces use default shader -extern cvar_t *r_roundImagesDown; -extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage -extern cvar_t *r_picmip; // controls picmip values -extern cvar_t *r_finish; -extern cvar_t *r_textureMode; -extern cvar_t *r_offsetFactor; -extern cvar_t *r_offsetUnits; - -extern cvar_t *r_fullbright; // avoid lightmap pass -extern cvar_t *r_lightmap; // render lightmaps only -extern cvar_t *r_vertexLight; // vertex lighting mode for better performance -extern cvar_t *r_uiFullScreen; // ui is running fullscreen - -extern cvar_t *r_logFile; // number of frames to emit GL logs -extern cvar_t *r_showtris; // enables wireframe rendering of the world -extern cvar_t *r_showsky; // forces sky in front of all surfaces -extern cvar_t *r_shownormals; // draws wireframe normals -extern cvar_t *r_clear; // force screen clear every frame - -extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection -extern cvar_t *r_flares; // light flares - -extern cvar_t *r_intensity; - -extern cvar_t *r_lockpvs; -extern cvar_t *r_noportals; -extern cvar_t *r_portalOnly; - -extern cvar_t *r_subdivisions; -extern cvar_t *r_lodCurveError; -extern cvar_t *r_skipBackEnd; - -extern cvar_t *r_anaglyphMode; - -extern cvar_t *r_mergeMultidraws; -extern cvar_t *r_mergeLeafSurfaces; - -extern cvar_t *r_softOverbright; - -extern cvar_t *r_hdr; -extern cvar_t *r_floatLightmap; -extern cvar_t *r_postProcess; - -extern cvar_t *r_toneMap; -extern cvar_t *r_forceToneMap; -extern cvar_t *r_forceToneMapMin; -extern cvar_t *r_forceToneMapAvg; -extern cvar_t *r_forceToneMapMax; - -extern cvar_t *r_autoExposure; -extern cvar_t *r_forceAutoExposure; -extern cvar_t *r_forceAutoExposureMin; -extern cvar_t *r_forceAutoExposureMax; - -extern cvar_t *r_cameraExposure; - -extern cvar_t *r_srgb; - -extern cvar_t *r_depthPrepass; -extern cvar_t *r_ssao; - -extern cvar_t *r_normalMapping; -extern cvar_t *r_specularMapping; -extern cvar_t *r_deluxeMapping; -extern cvar_t *r_parallaxMapping; -extern cvar_t *r_cubeMapping; -extern cvar_t *r_deluxeSpecular; -extern cvar_t *r_specularIsMetallic; -extern cvar_t *r_baseSpecular; -extern cvar_t *r_baseGloss; -extern cvar_t *r_dlightMode; -extern cvar_t *r_pshadowDist; -extern cvar_t *r_recalcMD3Normals; -extern cvar_t *r_mergeLightmaps; -extern cvar_t *r_imageUpsample; -extern cvar_t *r_imageUpsampleMaxSize; -extern cvar_t *r_imageUpsampleType; -extern cvar_t *r_genNormalMaps; -extern cvar_t *r_forceSun; -extern cvar_t *r_forceSunMapLightScale; -extern cvar_t *r_forceSunLightScale; -extern cvar_t *r_forceSunAmbientScale; -extern cvar_t *r_sunlightMode; -extern cvar_t *r_drawSunRays; -extern cvar_t *r_sunShadows; -extern cvar_t *r_shadowFilter; -extern cvar_t *r_shadowMapSize; -extern cvar_t *r_shadowCascadeZNear; -extern cvar_t *r_shadowCascadeZFar; -extern cvar_t *r_shadowCascadeZBias; -extern cvar_t *r_ignoreDstAlpha; - -extern cvar_t *r_greyscale; - -extern cvar_t *r_ignoreGLErrors; - -extern cvar_t *r_overBrightBits; -extern cvar_t *r_mapOverBrightBits; - -extern cvar_t *r_debugSurface; -extern cvar_t *r_simpleMipMaps; - -extern cvar_t *r_showImages; -extern cvar_t *r_debugSort; - -extern cvar_t *r_printShaders; - -extern cvar_t *r_marksOnTriangleMeshes; - -//==================================================================== - -void R_SwapBuffers( int ); - -void R_RenderView( viewParms_t *parms ); -void R_RenderDlightCubemaps(const refdef_t *fd); -void R_RenderPshadowMaps(const refdef_t *fd); -void R_RenderSunShadowMaps(const refdef_t *fd, int level); -void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene ); - -void R_AddMD3Surfaces( trRefEntity_t *e ); -void R_AddNullModelSurfaces( trRefEntity_t *e ); -void R_AddBeamSurfaces( trRefEntity_t *e ); -void R_AddRailSurfaces( trRefEntity_t *e, qboolean isUnderwater ); -void R_AddLightningBoltSurfaces( trRefEntity_t *e ); - -void R_AddPolygonSurfaces( void ); - -void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, - int *fogNum, int *dlightMap, int *pshadowMap ); - -void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, - int fogIndex, int dlightMap, int pshadowMap, int cubemap ); - -void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2); -qboolean R_CalcTangentVectors(srfVert_t * dv[3]); - -#define CULL_IN 0 // completely unclipped -#define CULL_CLIP 1 // clipped by one or more planes -#define CULL_OUT 2 // completely outside the clipping planes -void R_LocalNormalToWorld (const vec3_t local, vec3_t world); -void R_LocalPointToWorld (const vec3_t local, vec3_t world); -int R_CullBox (vec3_t bounds[2]); -int R_CullLocalBox (vec3_t bounds[2]); -int R_CullPointAndRadiusEx( const vec3_t origin, float radius, const cplane_t* frustum, int numPlanes ); -int R_CullPointAndRadius( const vec3_t origin, float radius ); -int R_CullLocalPointAndRadius( const vec3_t origin, float radius ); - -void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, qboolean computeFrustum); -void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *or ); - -/* -** GL wrapper/helper functions -*/ -void GL_Bind( image_t *image ); -void GL_BindToTMU( image_t *image, int tmu ); -void GL_SetDefaultState (void); -void GL_SelectTexture( int unit ); -void GL_TextureMode( const char *string ); -void GL_CheckErrs( char *file, int line ); -#define GL_CheckErrors(...) GL_CheckErrs(__FILE__, __LINE__) -void GL_State( unsigned long stateVector ); -void GL_SetProjectionMatrix(mat4_t matrix); -void GL_SetModelviewMatrix(mat4_t matrix); -void GL_TexEnv( int env ); -void GL_Cull( int cullType ); - -#define GLS_SRCBLEND_ZERO 0x00000001 -#define GLS_SRCBLEND_ONE 0x00000002 -#define GLS_SRCBLEND_DST_COLOR 0x00000003 -#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004 -#define GLS_SRCBLEND_SRC_ALPHA 0x00000005 -#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006 -#define GLS_SRCBLEND_DST_ALPHA 0x00000007 -#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008 -#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009 -#define GLS_SRCBLEND_BITS 0x0000000f - -#define GLS_DSTBLEND_ZERO 0x00000010 -#define GLS_DSTBLEND_ONE 0x00000020 -#define GLS_DSTBLEND_SRC_COLOR 0x00000030 -#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040 -#define GLS_DSTBLEND_SRC_ALPHA 0x00000050 -#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060 -#define GLS_DSTBLEND_DST_ALPHA 0x00000070 -#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080 -#define GLS_DSTBLEND_BITS 0x000000f0 - -#define GLS_DEPTHMASK_TRUE 0x00000100 - -#define GLS_POLYMODE_LINE 0x00001000 - -#define GLS_DEPTHTEST_DISABLE 0x00010000 -#define GLS_DEPTHFUNC_EQUAL 0x00020000 -#define GLS_DEPTHFUNC_GREATER 0x00040000 -#define GLS_DEPTHFUNC_BITS 0x00060000 - -#define GLS_ATEST_GT_0 0x10000000 -#define GLS_ATEST_LT_80 0x20000000 -#define GLS_ATEST_GE_80 0x40000000 -#define GLS_ATEST_BITS 0x70000000 - -#define GLS_DEFAULT GLS_DEPTHMASK_TRUE - -void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); -void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); - -void RE_BeginFrame( stereoFrame_t stereoFrame ); -void RE_BeginRegistration( glconfig_t *glconfig ); -void RE_LoadWorldMap( const char *mapname ); -void RE_SetWorldVisData( const byte *vis ); -qhandle_t RE_RegisterModel( const char *name ); -qhandle_t RE_RegisterSkin( const char *name ); -void RE_Shutdown( qboolean destroyWindow ); - -qboolean R_GetEntityToken( char *buffer, int size ); - -model_t *R_AllocModel( void ); - -void R_Init( void ); -void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height ); - -void R_SetColorMappings( void ); -void R_GammaCorrect( byte *buffer, int bufSize ); - -void R_ImageList_f( void ); -void R_SkinList_f( void ); -// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516 -const void *RB_TakeScreenshotCmd( const void *data ); -void R_ScreenShot_f( void ); - -void R_InitFogTable( void ); -float R_FogFactor( float s, float t ); -void R_InitImages( void ); -void R_DeleteTextures( void ); -int R_SumOfUsedImages( void ); -void R_InitSkins( void ); -skin_t *R_GetSkinByHandle( qhandle_t hSkin ); - -int R_ComputeLOD( trRefEntity_t *ent ); - -const void *RB_TakeVideoFrameCmd( const void *data ); - -// -// tr_shader.c -// -shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ); -shader_t *R_GetShaderByHandle( qhandle_t hShader ); -shader_t *R_GetShaderByState( int index, long *cycleTime ); -shader_t *R_FindShaderByName( const char *name ); -void R_InitShaders( void ); -void R_ShaderList_f( void ); -void R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset); - -/* -==================================================================== - -IMPLEMENTATION SPECIFIC FUNCTIONS - -==================================================================== -*/ - -void GLimp_InitExtraExtensions( void ); - -/* -==================================================================== - -TESSELATOR/SHADER DECLARATIONS - -==================================================================== -*/ - -typedef struct stageVars -{ - color4ub_t colors[SHADER_MAX_VERTEXES]; - vec2_t texcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES]; -} stageVars_t; - -#define MAX_MULTIDRAW_PRIMITIVES 16384 - -typedef struct shaderCommands_s -{ - glIndex_t indexes[SHADER_MAX_INDEXES] QALIGN(16); - vec4_t xyz[SHADER_MAX_VERTEXES] QALIGN(16); - uint32_t normal[SHADER_MAX_VERTEXES] QALIGN(16); -#ifdef USE_VERT_TANGENT_SPACE - uint32_t tangent[SHADER_MAX_VERTEXES] QALIGN(16); -#endif - vec2_t texCoords[SHADER_MAX_VERTEXES][2] QALIGN(16); - vec4_t vertexColors[SHADER_MAX_VERTEXES] QALIGN(16); - uint32_t lightdir[SHADER_MAX_VERTEXES] QALIGN(16); - //int vertexDlightBits[SHADER_MAX_VERTEXES] QALIGN(16); - - VBO_t *vbo; - IBO_t *ibo; - qboolean useInternalVBO; - - stageVars_t svars QALIGN(16); - - //color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16); - - shader_t *shader; - float shaderTime; - int fogNum; - int cubemapIndex; - - int dlightBits; // or together of all vertexDlightBits - int pshadowBits; - - int firstIndex; - int numIndexes; - int numVertexes; - glIndex_t minIndex; - glIndex_t maxIndex; - - int multiDrawPrimitives; - GLsizei multiDrawNumIndexes[MAX_MULTIDRAW_PRIMITIVES]; - glIndex_t *multiDrawFirstIndex[MAX_MULTIDRAW_PRIMITIVES]; - glIndex_t *multiDrawLastIndex[MAX_MULTIDRAW_PRIMITIVES]; - glIndex_t multiDrawMinIndex[MAX_MULTIDRAW_PRIMITIVES]; - glIndex_t multiDrawMaxIndex[MAX_MULTIDRAW_PRIMITIVES]; - - // info extracted from current shader - int numPasses; - void (*currentStageIteratorFunc)( void ); - shaderStage_t **xstages; -} shaderCommands_t; - -extern shaderCommands_t tess; - -void RB_BeginSurface(shader_t *shader, int fogNum, int cubemapIndex ); -void RB_EndSurface(void); -void RB_CheckOverflow( int verts, int indexes ); -#define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);} - -void R_DrawElementsVBO( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ); -void RB_StageIteratorGeneric( void ); -void RB_StageIteratorSky( void ); -void RB_StageIteratorVertexLitTexture( void ); -void RB_StageIteratorLightmappedMultitexture( void ); - -void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, float color[4] ); -void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], float s1, float t1, float s2, float t2 ); -void RB_InstantQuad( vec4_t quadVerts[4] ); -//void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4], vec4_t color, shaderProgram_t *sp, vec2_t invTexRes); -void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4]); - -void RB_ShowImages( void ); - - -/* -============================================================ - -WORLD MAP - -============================================================ -*/ - -void R_AddBrushModelSurfaces( trRefEntity_t *e ); -void R_AddWorldSurfaces( void ); -qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ); - - -/* -============================================================ - -FLARES - -============================================================ -*/ - -void R_ClearFlares( void ); - -void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ); -void RB_AddDlightFlares( void ); -void RB_RenderFlares (void); - -/* -============================================================ - -LIGHTS - -============================================================ -*/ - -void R_DlightBmodel( bmodel_t *bmodel ); -void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ); -void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or ); -int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); -int R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *world ); -int R_CubemapForPoint( vec3_t point ); - - -/* -============================================================ - -SHADOWS - -============================================================ -*/ - -void RB_ShadowTessEnd( void ); -void RB_ShadowFinish( void ); -void RB_ProjectionShadowDeform( void ); - -/* -============================================================ - -SKIES - -============================================================ -*/ - -void R_BuildCloudData( shaderCommands_t *shader ); -void R_InitSkyTexCoords( float cloudLayerHeight ); -void R_DrawSkyBox( shaderCommands_t *shader ); -void RB_DrawSun( float scale, shader_t *shader ); -void RB_ClipSkyPolygons( shaderCommands_t *shader ); - -/* -============================================================ - -CURVE TESSELATION - -============================================================ -*/ - -#define PATCH_STITCHING - -srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, - srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ); -srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ); -srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ); -void R_FreeSurfaceGridMesh( srfBspSurface_t *grid ); - -/* -============================================================ - -MARKERS, POLYGON PROJECTION ON WORLD POLYGONS - -============================================================ -*/ - -int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, - int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ); - - -/* -============================================================ - -VERTEX BUFFER OBJECTS - -============================================================ -*/ - -uint32_t R_VboPackTangent(vec4_t v); -uint32_t R_VboPackNormal(vec3_t v); -void R_VboUnpackTangent(vec4_t v, uint32_t b); -void R_VboUnpackNormal(vec3_t v, uint32_t b); - -VBO_t *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, vboUsage_t usage); -VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vertexes, uint32_t stateBits, vboUsage_t usage); - -IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, vboUsage_t usage); -IBO_t *R_CreateIBO2(const char *name, int numIndexes, glIndex_t * inIndexes, vboUsage_t usage); - -void R_BindVBO(VBO_t * vbo); -void R_BindNullVBO(void); - -void R_BindIBO(IBO_t * ibo); -void R_BindNullIBO(void); - -void R_InitVBOs(void); -void R_ShutdownVBOs(void); -void R_VBOList_f(void); - -void RB_UpdateVBOs(unsigned int attribBits); - - -/* -============================================================ - -GLSL - -============================================================ -*/ - -void GLSL_InitGPUShaders(void); -void GLSL_ShutdownGPUShaders(void); -void GLSL_VertexAttribsState(uint32_t stateBits); -void GLSL_VertexAttribPointers(uint32_t attribBits); -void GLSL_BindProgram(shaderProgram_t * program); -void GLSL_BindNullProgram(void); - -void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value); -void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value); -void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v); -void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v); -void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v); -void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v); -void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix); - -shaderProgram_t *GLSL_GetGenericShaderProgram(int stage); - -/* -============================================================ - -SCENE GENERATION - -============================================================ -*/ - -void R_InitNextFrame( void ); - -void RE_ClearScene( void ); -void RE_AddRefEntityToScene( const refEntity_t *ent ); -void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ); -void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ); -void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ); -void RE_BeginScene( const refdef_t *fd ); -void RE_RenderScene( const refdef_t *fd ); -void RE_EndScene( void ); - -/* -============================================================= - -UNCOMPRESSING BONES - -============================================================= -*/ - -#define MC_BITS_X (16) -#define MC_BITS_Y (16) -#define MC_BITS_Z (16) -#define MC_BITS_VECT (16) - -#define MC_SCALE_X (1.0f/64) -#define MC_SCALE_Y (1.0f/64) -#define MC_SCALE_Z (1.0f/64) - -void MC_UnCompress(float mat[3][4],const unsigned char * comp); - -/* -============================================================= - -ANIMATED MODELS - -============================================================= -*/ - -void R_MDRAddAnimSurfaces( trRefEntity_t *ent ); -void RB_MDRSurfaceAnim( mdrSurface_t *surface ); -qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name ); -void R_AddIQMSurfaces( trRefEntity_t *ent ); -void RB_IQMSurfaceAnim( surfaceType_t *surface ); -int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, - int startFrame, int endFrame, - float frac, const char *tagName ); - -/* -============================================================= - -IMAGE LOADERS - -============================================================= -*/ - -void R_LoadBMP( const char *name, byte **pic, int *width, int *height ); -void R_LoadJPG( const char *name, byte **pic, int *width, int *height ); -void R_LoadPCX( const char *name, byte **pic, int *width, int *height ); -void R_LoadPNG( const char *name, byte **pic, int *width, int *height ); -void R_LoadTGA( const char *name, byte **pic, int *width, int *height ); - -/* -============================================================= -============================================================= -*/ -void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix, - vec4_t eye, vec4_t dst ); -void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ); - -void RB_DeformTessGeometry( void ); - -void RB_CalcFogTexCoords( float *dstTexCoords ); - -void RB_CalcScaleTexMatrix( const float scale[2], float *matrix ); -void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix ); -void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix ); -void RB_CalcTurbulentFactors( const waveForm_t *wf, float *amplitude, float *now ); -void RB_CalcTransformTexMatrix( const texModInfo_t *tmi, float *matrix ); -void RB_CalcStretchTexMatrix( const waveForm_t *wf, float *matrix ); - -void RB_CalcModulateColorsByFog( unsigned char *dstColors ); -float RB_CalcWaveAlphaSingle( const waveForm_t *wf ); -float RB_CalcWaveColorSingle( const waveForm_t *wf ); - -/* -============================================================= - -RENDERER BACK END FUNCTIONS - -============================================================= -*/ - -void RB_ExecuteRenderCommands( const void *data ); - -/* -============================================================= - -RENDERER BACK END COMMAND QUEUE - -============================================================= -*/ - -#define MAX_RENDER_COMMANDS 0x40000 - -typedef struct { - byte cmds[MAX_RENDER_COMMANDS]; - int used; -} renderCommandList_t; - -typedef struct { - int commandId; - float color[4]; -} setColorCommand_t; - -typedef struct { - int commandId; - int buffer; -} drawBufferCommand_t; - -typedef struct { - int commandId; - image_t *image; - int width; - int height; - void *data; -} subImageCommand_t; - -typedef struct { - int commandId; -} swapBuffersCommand_t; - -typedef struct { - int commandId; - int buffer; -} endFrameCommand_t; - -typedef struct { - int commandId; - shader_t *shader; - float x, y; - float w, h; - float s1, t1; - float s2, t2; -} stretchPicCommand_t; - -typedef struct { - int commandId; - trRefdef_t refdef; - viewParms_t viewParms; - drawSurf_t *drawSurfs; - int numDrawSurfs; -} drawSurfsCommand_t; - -typedef struct { - int commandId; - int x; - int y; - int width; - int height; - char *fileName; - qboolean jpeg; -} screenshotCommand_t; - -typedef struct { - int commandId; - int width; - int height; - byte *captureBuffer; - byte *encodeBuffer; - qboolean motionJpeg; -} videoFrameCommand_t; - -typedef struct -{ - int commandId; - - GLboolean rgba[4]; -} colorMaskCommand_t; - -typedef struct -{ - int commandId; -} clearDepthCommand_t; - -typedef struct { - int commandId; - int map; - int cubeSide; -} capShadowmapCommand_t; - -typedef struct { - int commandId; - trRefdef_t refdef; - viewParms_t viewParms; -} postProcessCommand_t; - -typedef enum { - RC_END_OF_LIST, - RC_SET_COLOR, - RC_STRETCH_PIC, - RC_DRAW_SURFS, - RC_DRAW_BUFFER, - RC_SWAP_BUFFERS, - RC_SCREENSHOT, - RC_VIDEOFRAME, - RC_COLORMASK, - RC_CLEARDEPTH, - RC_CAPSHADOWMAP, - RC_POSTPROCESS -} renderCommand_t; - - -// these are sort of arbitrary limits. -// the limits apply to the sum of all scenes in a frame -- -// the main view, all the 3D icons, etc -#define MAX_POLYS 600 -#define MAX_POLYVERTS 3000 - -// all of the information needed by the back end must be -// contained in a backEndData_t -typedef struct { - drawSurf_t drawSurfs[MAX_DRAWSURFS]; - dlight_t dlights[MAX_DLIGHTS]; - trRefEntity_t entities[MAX_REFENTITIES]; - srfPoly_t *polys;//[MAX_POLYS]; - polyVert_t *polyVerts;//[MAX_POLYVERTS]; - pshadow_t pshadows[MAX_CALC_PSHADOWS]; - renderCommandList_t commands; -} backEndData_t; - -extern int max_polys; -extern int max_polyverts; - -extern backEndData_t *backEndData; // the second one may not be allocated - - -void *R_GetCommandBuffer( int bytes ); -void RB_ExecuteRenderCommands( const void *data ); - -void R_IssuePendingRenderCommands( void ); - -void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ); -void R_AddCapShadowmapCmd( int dlight, int cubeSide ); -void R_AddPostProcessCmd (void); - -void RE_SetColor( const float *rgba ); -void RE_StretchPic ( float x, float y, float w, float h, - float s1, float t1, float s2, float t2, qhandle_t hShader ); -void RE_BeginFrame( stereoFrame_t stereoFrame ); -void RE_EndFrame( int *frontEndMsec, int *backEndMsec ); -void RE_SaveJPG(char * filename, int quality, int image_width, int image_height, - unsigned char *image_buffer, int padding); -size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, - int image_width, int image_height, byte *image_buffer, int padding); -void RE_TakeVideoFrame( int width, int height, - byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ); - - -#endif //TR_LOCAL_H diff --git a/code/renderergl2/tr_main.c b/code/renderergl2/tr_main.c deleted file mode 100644 index df1f8e60c9..0000000000 --- a/code/renderergl2/tr_main.c +++ /dev/null @@ -1,2913 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_main.c -- main control flow for each frame - -#include "tr_local.h" - -#include // memcpy - -trGlobals_t tr; - -static float s_flipMatrix[16] = { - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 -}; - - -refimport_t ri; - -// entities that will have procedurally generated surfaces will just -// point at this for their sorting surface -surfaceType_t entitySurface = SF_ENTITY; - -/* -================ -R_CompareVert -================ -*/ -qboolean R_CompareVert(srfVert_t * v1, srfVert_t * v2, qboolean checkST) -{ - int i; - - for(i = 0; i < 3; i++) - { - if(floor(v1->xyz[i] + 0.1) != floor(v2->xyz[i] + 0.1)) - { - return qfalse; - } - - if(checkST && ((v1->st[0] != v2->st[0]) || (v1->st[1] != v2->st[1]))) - { - return qfalse; - } - } - - return qtrue; -} - -/* -============= -R_CalcNormalForTriangle -============= -*/ -void R_CalcNormalForTriangle(vec3_t normal, const vec3_t v0, const vec3_t v1, const vec3_t v2) -{ - vec3_t udir, vdir; - - // compute the face normal based on vertex points - VectorSubtract(v2, v0, udir); - VectorSubtract(v1, v0, vdir); - CrossProduct(udir, vdir, normal); - - VectorNormalize(normal); -} - -/* -============= -R_CalcTangentsForTriangle -http://members.rogers.com/deseric/tangentspace.htm -============= -*/ -void R_CalcTangentsForTriangle(vec3_t tangent, vec3_t bitangent, - const vec3_t v0, const vec3_t v1, const vec3_t v2, - const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - int i; - vec3_t planes[3]; - vec3_t u, v; - - for(i = 0; i < 3; i++) - { - VectorSet(u, v1[i] - v0[i], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[i] - v0[i], t2[0] - t0[0], t2[1] - t0[1]); - - VectorNormalize(u); - VectorNormalize(v); - - CrossProduct(u, v, planes[i]); - } - - //So your tangent space will be defined by this : - //Normal = Normal of the triangle or Tangent X Bitangent (careful with the cross product, - // you have to make sure the normal points in the right direction) - //Tangent = ( dp(Fx(s,t)) / ds, dp(Fy(s,t)) / ds, dp(Fz(s,t)) / ds ) or ( -Bx/Ax, -By/Ay, - Bz/Az ) - //Bitangent = ( dp(Fx(s,t)) / dt, dp(Fy(s,t)) / dt, dp(Fz(s,t)) / dt ) or ( -Cx/Ax, -Cy/Ay, -Cz/Az ) - - // tangent... - tangent[0] = -planes[0][1] / planes[0][0]; - tangent[1] = -planes[1][1] / planes[1][0]; - tangent[2] = -planes[2][1] / planes[2][0]; - VectorNormalize(tangent); - - // bitangent... - bitangent[0] = -planes[0][2] / planes[0][0]; - bitangent[1] = -planes[1][2] / planes[1][0]; - bitangent[2] = -planes[2][2] / planes[2][0]; - VectorNormalize(bitangent); -} - - - - -/* -============= -R_CalcTangentSpace -============= -*/ -void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - vec3_t cp, u, v; - vec3_t faceNormal; - - VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]); - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[0] = -cp[1] / cp[0]; - bitangent[0] = -cp[2] / cp[0]; - } - - u[0] = v1[1] - v0[1]; - v[0] = v2[1] - v0[1]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[1] = -cp[1] / cp[0]; - bitangent[1] = -cp[2] / cp[0]; - } - - u[0] = v1[2] - v0[2]; - v[0] = v2[2] - v0[2]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[2] = -cp[1] / cp[0]; - bitangent[2] = -cp[2] / cp[0]; - } - - VectorNormalize(tangent); - VectorNormalize(bitangent); - - // compute the face normal based on vertex points - if ( normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f ) - { - VectorSubtract(v2, v0, u); - VectorSubtract(v1, v0, v); - CrossProduct(u, v, faceNormal); - } - else - { - VectorCopy(normal, faceNormal); - } - - VectorNormalize(faceNormal); - -#if 1 - // Gram-Schmidt orthogonalize - //tangent[a] = (t - n * Dot(n, t)).Normalize(); - VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent); - VectorNormalize(tangent); - - // compute the cross product B=NxT - //CrossProduct(normal, tangent, bitangent); -#else - // normal, compute the cross product N=TxB - CrossProduct(tangent, bitangent, normal); - VectorNormalize(normal); - - if(DotProduct(normal, faceNormal) < 0) - { - //VectorInverse(normal); - //VectorInverse(tangent); - //VectorInverse(bitangent); - - // compute the cross product T=BxN - CrossProduct(bitangent, faceNormal, tangent); - - // compute the cross product B=NxT - //CrossProduct(normal, tangent, bitangent); - } -#endif - - VectorCopy(faceNormal, normal); -} - -void R_CalcTangentSpaceFast(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - vec3_t cp, u, v; - vec3_t faceNormal; - - VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]); - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[0] = -cp[1] / cp[0]; - bitangent[0] = -cp[2] / cp[0]; - } - - u[0] = v1[1] - v0[1]; - v[0] = v2[1] - v0[1]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[1] = -cp[1] / cp[0]; - bitangent[1] = -cp[2] / cp[0]; - } - - u[0] = v1[2] - v0[2]; - v[0] = v2[2] - v0[2]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[2] = -cp[1] / cp[0]; - bitangent[2] = -cp[2] / cp[0]; - } - - VectorNormalizeFast(tangent); - VectorNormalizeFast(bitangent); - - // compute the face normal based on vertex points - VectorSubtract(v2, v0, u); - VectorSubtract(v1, v0, v); - CrossProduct(u, v, faceNormal); - - VectorNormalizeFast(faceNormal); - -#if 0 - // normal, compute the cross product N=TxB - CrossProduct(tangent, bitangent, normal); - VectorNormalizeFast(normal); - - if(DotProduct(normal, faceNormal) < 0) - { - VectorInverse(normal); - //VectorInverse(tangent); - //VectorInverse(bitangent); - - CrossProduct(normal, tangent, bitangent); - } - - VectorCopy(faceNormal, normal); -#else - // Gram-Schmidt orthogonalize - //tangent[a] = (t - n * Dot(n, t)).Normalize(); - VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent); - VectorNormalizeFast(tangent); -#endif - - VectorCopy(faceNormal, normal); -} - -/* -http://www.terathon.com/code/tangent.html -*/ -void R_CalcTBN(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v1, const vec3_t v2, const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3) -{ - vec3_t u, v; - float x1, x2, y1, y2, z1, z2; - float s1, s2, t1, t2; - float r, dot; - - x1 = v2[0] - v1[0]; - x2 = v3[0] - v1[0]; - y1 = v2[1] - v1[1]; - y2 = v3[1] - v1[1]; - z1 = v2[2] - v1[2]; - z2 = v3[2] - v1[2]; - - s1 = w2[0] - w1[0]; - s2 = w3[0] - w1[0]; - t1 = w2[1] - w1[1]; - t2 = w3[1] - w1[1]; - - r = 1.0f / (s1 * t2 - s2 * t1); - - VectorSet(tangent, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); - VectorSet(bitangent, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); - - // compute the face normal based on vertex points - VectorSubtract(v3, v1, u); - VectorSubtract(v2, v1, v); - CrossProduct(u, v, normal); - - VectorNormalize(normal); - - // Gram-Schmidt orthogonalize - //tangent[a] = (t - n * Dot(n, t)).Normalize(); - dot = DotProduct(normal, tangent); - VectorMA(tangent, -dot, normal, tangent); - VectorNormalize(tangent); - - // B=NxT - //CrossProduct(normal, tangent, bitangent); -} - -void R_CalcTBN2(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v1, const vec3_t v2, const vec3_t v3, const vec2_t t1, const vec2_t t2, const vec2_t t3) -{ - vec3_t v2v1; - vec3_t v3v1; - - float c2c1_T; - float c2c1_B; - - float c3c1_T; - float c3c1_B; - - float denominator; - float scale1, scale2; - - vec3_t T, B, N, C; - - - // Calculate the tangent basis for each vertex of the triangle - // UPDATE: In the 3rd edition of the accompanying article, the for-loop located here has - // been removed as it was redundant (the entire TBN matrix was calculated three times - // instead of just one). - // - // Please note, that this function relies on the fact that the input geometry are triangles - // and the tangent basis for each vertex thus is identical! - // - - // Calculate the vectors from the current vertex to the two other vertices in the triangle - VectorSubtract(v2, v1, v2v1); - VectorSubtract(v3, v1, v3v1); - - // The equation presented in the article states that: - // c2c1_T = V2.texcoord.x - V1.texcoord.x - // c2c1_B = V2.texcoord.y - V1.texcoord.y - // c3c1_T = V3.texcoord.x - V1.texcoord.x - // c3c1_B = V3.texcoord.y - V1.texcoord.y - - // Calculate c2c1_T and c2c1_B - c2c1_T = t2[0] - t1[0]; - c2c1_B = t2[1] - t2[1]; - - // Calculate c3c1_T and c3c1_B - c3c1_T = t3[0] - t1[0]; - c3c1_B = t3[1] - t1[1]; - - denominator = c2c1_T * c3c1_B - c3c1_T * c2c1_B; - //if(ROUNDOFF(fDenominator) == 0.0f) - if(denominator == 0.0f) - { - // We won't risk a divide by zero, so set the tangent matrix to the identity matrix - VectorSet(tangent, 1, 0, 0); - VectorSet(bitangent, 0, 1, 0); - VectorSet(normal, 0, 0, 1); - } - else - { - // Calculate the reciprocal value once and for all (to achieve speed) - scale1 = 1.0f / denominator; - - // T and B are calculated just as the equation in the article states - VectorSet(T, (c3c1_B * v2v1[0] - c2c1_B * v3v1[0]) * scale1, - (c3c1_B * v2v1[1] - c2c1_B * v3v1[1]) * scale1, - (c3c1_B * v2v1[2] - c2c1_B * v3v1[2]) * scale1); - - VectorSet(B, (-c3c1_T * v2v1[0] + c2c1_T * v3v1[0]) * scale1, - (-c3c1_T * v2v1[1] + c2c1_T * v3v1[1]) * scale1, - (-c3c1_T * v2v1[2] + c2c1_T * v3v1[2]) * scale1); - - // The normal N is calculated as the cross product between T and B - CrossProduct(T, B, N); - -#if 0 - VectorCopy(T, tangent); - VectorCopy(B, bitangent); - VectorCopy(N, normal); -#else - // Calculate the reciprocal value once and for all (to achieve speed) - scale2 = 1.0f / ((T[0] * B[1] * N[2] - T[2] * B[1] * N[0]) + - (B[0] * N[1] * T[2] - B[2] * N[1] * T[0]) + - (N[0] * T[1] * B[2] - N[2] * T[1] * B[0])); - - // Calculate the inverse if the TBN matrix using the formula described in the article. - // We store the basis vectors directly in the provided TBN matrix: pvTBNMatrix - CrossProduct(B, N, C); tangent[0] = C[0] * scale2; - CrossProduct(N, T, C); tangent[1] = -C[0] * scale2; - CrossProduct(T, B, C); tangent[2] = C[0] * scale2; - VectorNormalize(tangent); - - CrossProduct(B, N, C); bitangent[0] = -C[1] * scale2; - CrossProduct(N, T, C); bitangent[1] = C[1] * scale2; - CrossProduct(T, B, C); bitangent[2] = -C[1] * scale2; - VectorNormalize(bitangent); - - CrossProduct(B, N, C); normal[0] = C[2] * scale2; - CrossProduct(N, T, C); normal[1] = -C[2] * scale2; - CrossProduct(T, B, C); normal[2] = C[2] * scale2; - VectorNormalize(normal); -#endif - } -} - - -#ifdef USE_VERT_TANGENT_SPACE -qboolean R_CalcTangentVectors(srfVert_t * dv[3]) -{ - int i; - float bb, s, t; - vec3_t bary; - - - /* calculate barycentric basis for the triangle */ - bb = (dv[1]->st[0] - dv[0]->st[0]) * (dv[2]->st[1] - dv[0]->st[1]) - (dv[2]->st[0] - dv[0]->st[0]) * (dv[1]->st[1] - dv[0]->st[1]); - if(fabs(bb) < 0.00000001f) - return qfalse; - - /* do each vertex */ - for(i = 0; i < 3; i++) - { - vec3_t bitangent, nxt; - - // calculate s tangent vector - s = dv[i]->st[0] + 10.0f; - t = dv[i]->st[1]; - bary[0] = ((dv[1]->st[0] - s) * (dv[2]->st[1] - t) - (dv[2]->st[0] - s) * (dv[1]->st[1] - t)) / bb; - bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb; - bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb; - - dv[i]->tangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0]; - dv[i]->tangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1]; - dv[i]->tangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2]; - - VectorSubtract(dv[i]->tangent, dv[i]->xyz, dv[i]->tangent); - VectorNormalize(dv[i]->tangent); - - // calculate t tangent vector - s = dv[i]->st[0]; - t = dv[i]->st[1] + 10.0f; - bary[0] = ((dv[1]->st[0] - s) * (dv[2]->st[1] - t) - (dv[2]->st[0] - s) * (dv[1]->st[1] - t)) / bb; - bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb; - bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb; - - bitangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0]; - bitangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1]; - bitangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2]; - - VectorSubtract(bitangent, dv[i]->xyz, bitangent); - VectorNormalize(bitangent); - - // store bitangent handedness - CrossProduct(dv[i]->normal, dv[i]->tangent, nxt); - dv[i]->tangent[3] = (DotProduct(nxt, bitangent) < 0.0f) ? -1.0f : 1.0f; - - // debug code - //% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i, - //% stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] ); - } - - return qtrue; -} -#endif - - -/* -================= -R_CullLocalBox - -Returns CULL_IN, CULL_CLIP, or CULL_OUT -================= -*/ -int R_CullLocalBox(vec3_t localBounds[2]) { -#if 0 - int i, j; - vec3_t transformed[8]; - float dists[8]; - vec3_t v; - cplane_t *frust; - int anyBack; - int front, back; - - if ( r_nocull->integer ) { - return CULL_CLIP; - } - - // transform into world space - for (i = 0 ; i < 8 ; i++) { - v[0] = bounds[i&1][0]; - v[1] = bounds[(i>>1)&1][1]; - v[2] = bounds[(i>>2)&1][2]; - - VectorCopy( tr.or.origin, transformed[i] ); - VectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] ); - VectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] ); - VectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] ); - } - - // check against frustum planes - anyBack = 0; - for (i = 0 ; i < 4 ; i++) { - frust = &tr.viewParms.frustum[i]; - - front = back = 0; - for (j = 0 ; j < 8 ; j++) { - dists[j] = DotProduct(transformed[j], frust->normal); - if ( dists[j] > frust->dist ) { - front = 1; - if ( back ) { - break; // a point is in front - } - } else { - back = 1; - } - } - if ( !front ) { - // all points were behind one of the planes - return CULL_OUT; - } - anyBack |= back; - } - - if ( !anyBack ) { - return CULL_IN; // completely inside frustum - } - - return CULL_CLIP; // partially clipped -#else - int j; - vec3_t transformed; - vec3_t v; - vec3_t worldBounds[2]; - - if(r_nocull->integer) - { - return CULL_CLIP; - } - - // transform into world space - ClearBounds(worldBounds[0], worldBounds[1]); - - for(j = 0; j < 8; j++) - { - v[0] = localBounds[j & 1][0]; - v[1] = localBounds[(j >> 1) & 1][1]; - v[2] = localBounds[(j >> 2) & 1][2]; - - R_LocalPointToWorld(v, transformed); - - AddPointToBounds(transformed, worldBounds[0], worldBounds[1]); - } - - return R_CullBox(worldBounds); -#endif -} - -/* -================= -R_CullBox - -Returns CULL_IN, CULL_CLIP, or CULL_OUT -================= -*/ -int R_CullBox(vec3_t worldBounds[2]) { - int i; - cplane_t *frust; - qboolean anyClip; - int r, numPlanes; - - numPlanes = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4; - - // check against frustum planes - anyClip = qfalse; - for(i = 0; i < numPlanes; i++) - { - frust = &tr.viewParms.frustum[i]; - - r = BoxOnPlaneSide(worldBounds[0], worldBounds[1], frust); - - if(r == 2) - { - // completely outside frustum - return CULL_OUT; - } - if(r == 3) - { - anyClip = qtrue; - } - } - - if(!anyClip) - { - // completely inside frustum - return CULL_IN; - } - - // partially clipped - return CULL_CLIP; -} - -/* -** R_CullLocalPointAndRadius -*/ -int R_CullLocalPointAndRadius( const vec3_t pt, float radius ) -{ - vec3_t transformed; - - R_LocalPointToWorld( pt, transformed ); - - return R_CullPointAndRadius( transformed, radius ); -} - -/* -** R_CullPointAndRadius -*/ -int R_CullPointAndRadiusEx( const vec3_t pt, float radius, const cplane_t* frustum, int numPlanes ) -{ - int i; - float dist; - const cplane_t *frust; - qboolean mightBeClipped = qfalse; - - if ( r_nocull->integer ) { - return CULL_CLIP; - } - - // check against frustum planes - for (i = 0 ; i < numPlanes ; i++) - { - frust = &frustum[i]; - - dist = DotProduct( pt, frust->normal) - frust->dist; - if ( dist < -radius ) - { - return CULL_OUT; - } - else if ( dist <= radius ) - { - mightBeClipped = qtrue; - } - } - - if ( mightBeClipped ) - { - return CULL_CLIP; - } - - return CULL_IN; // completely inside frustum -} - -/* -** R_CullPointAndRadius -*/ -int R_CullPointAndRadius( const vec3_t pt, float radius ) -{ - return R_CullPointAndRadiusEx(pt, radius, tr.viewParms.frustum, (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4); -} - -/* -================= -R_LocalNormalToWorld - -================= -*/ -void R_LocalNormalToWorld (const vec3_t local, vec3_t world) { - world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0]; - world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1]; - world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2]; -} - -/* -================= -R_LocalPointToWorld - -================= -*/ -void R_LocalPointToWorld (const vec3_t local, vec3_t world) { - world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0] + tr.or.origin[0]; - world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1] + tr.or.origin[1]; - world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2] + tr.or.origin[2]; -} - -/* -================= -R_WorldToLocal - -================= -*/ -void R_WorldToLocal (const vec3_t world, vec3_t local) { - local[0] = DotProduct(world, tr.or.axis[0]); - local[1] = DotProduct(world, tr.or.axis[1]); - local[2] = DotProduct(world, tr.or.axis[2]); -} - -/* -========================== -R_TransformModelToClip - -========================== -*/ -void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix, - vec4_t eye, vec4_t dst ) { - int i; - - for ( i = 0 ; i < 4 ; i++ ) { - eye[i] = - src[0] * modelMatrix[ i + 0 * 4 ] + - src[1] * modelMatrix[ i + 1 * 4 ] + - src[2] * modelMatrix[ i + 2 * 4 ] + - 1 * modelMatrix[ i + 3 * 4 ]; - } - - for ( i = 0 ; i < 4 ; i++ ) { - dst[i] = - eye[0] * projectionMatrix[ i + 0 * 4 ] + - eye[1] * projectionMatrix[ i + 1 * 4 ] + - eye[2] * projectionMatrix[ i + 2 * 4 ] + - eye[3] * projectionMatrix[ i + 3 * 4 ]; - } -} - -/* -========================== -R_TransformClipToWindow - -========================== -*/ -void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) { - normalized[0] = clip[0] / clip[3]; - normalized[1] = clip[1] / clip[3]; - normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] ); - - window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth; - window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight; - window[2] = normalized[2]; - - window[0] = (int) ( window[0] + 0.5 ); - window[1] = (int) ( window[1] + 0.5 ); -} - - -/* -========================== -myGlMultMatrix - -========================== -*/ -void myGlMultMatrix( const float *a, const float *b, float *out ) { - int i, j; - - for ( i = 0 ; i < 4 ; i++ ) { - for ( j = 0 ; j < 4 ; j++ ) { - out[ i * 4 + j ] = - a [ i * 4 + 0 ] * b [ 0 * 4 + j ] - + a [ i * 4 + 1 ] * b [ 1 * 4 + j ] - + a [ i * 4 + 2 ] * b [ 2 * 4 + j ] - + a [ i * 4 + 3 ] * b [ 3 * 4 + j ]; - } - } -} - -/* -================= -R_RotateForEntity - -Generates an orientation for an entity and viewParms -Does NOT produce any GL calls -Called by both the front end and the back end -================= -*/ -void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, - orientationr_t *or ) { - float glMatrix[16]; - vec3_t delta; - float axisLength; - - if ( ent->e.reType != RT_MODEL ) { - *or = viewParms->world; - return; - } - - VectorCopy( ent->e.origin, or->origin ); - - VectorCopy( ent->e.axis[0], or->axis[0] ); - VectorCopy( ent->e.axis[1], or->axis[1] ); - VectorCopy( ent->e.axis[2], or->axis[2] ); - - glMatrix[0] = or->axis[0][0]; - glMatrix[4] = or->axis[1][0]; - glMatrix[8] = or->axis[2][0]; - glMatrix[12] = or->origin[0]; - - glMatrix[1] = or->axis[0][1]; - glMatrix[5] = or->axis[1][1]; - glMatrix[9] = or->axis[2][1]; - glMatrix[13] = or->origin[1]; - - glMatrix[2] = or->axis[0][2]; - glMatrix[6] = or->axis[1][2]; - glMatrix[10] = or->axis[2][2]; - glMatrix[14] = or->origin[2]; - - glMatrix[3] = 0; - glMatrix[7] = 0; - glMatrix[11] = 0; - glMatrix[15] = 1; - - Mat4Copy(glMatrix, or->transformMatrix); - myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix ); - - // calculate the viewer origin in the model's space - // needed for fog, specular, and environment mapping - VectorSubtract( viewParms->or.origin, or->origin, delta ); - - // compensate for scale in the axes if necessary - if ( ent->e.nonNormalizedAxes ) { - axisLength = VectorLength( ent->e.axis[0] ); - if ( !axisLength ) { - axisLength = 0; - } else { - axisLength = 1.0f / axisLength; - } - } else { - axisLength = 1.0f; - } - - or->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength; - or->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength; - or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength; -} - -/* -================= -R_RotateForViewer - -Sets up the modelview matrix for a given viewParm -================= -*/ -void R_RotateForViewer (void) -{ - float viewerMatrix[16]; - vec3_t origin; - - Com_Memset (&tr.or, 0, sizeof(tr.or)); - tr.or.axis[0][0] = 1; - tr.or.axis[1][1] = 1; - tr.or.axis[2][2] = 1; - VectorCopy (tr.viewParms.or.origin, tr.or.viewOrigin); - - // transform by the camera placement - VectorCopy( tr.viewParms.or.origin, origin ); - - viewerMatrix[0] = tr.viewParms.or.axis[0][0]; - viewerMatrix[4] = tr.viewParms.or.axis[0][1]; - viewerMatrix[8] = tr.viewParms.or.axis[0][2]; - viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8]; - - viewerMatrix[1] = tr.viewParms.or.axis[1][0]; - viewerMatrix[5] = tr.viewParms.or.axis[1][1]; - viewerMatrix[9] = tr.viewParms.or.axis[1][2]; - viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9]; - - viewerMatrix[2] = tr.viewParms.or.axis[2][0]; - viewerMatrix[6] = tr.viewParms.or.axis[2][1]; - viewerMatrix[10] = tr.viewParms.or.axis[2][2]; - viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10]; - - viewerMatrix[3] = 0; - viewerMatrix[7] = 0; - viewerMatrix[11] = 0; - viewerMatrix[15] = 1; - - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.or.modelMatrix ); - - tr.viewParms.world = tr.or; - -} - -/* -** SetFarClip -*/ -static void R_SetFarClip( void ) -{ - float farthestCornerDistance = 0; - int i; - - // if not rendering the world (icons, menus, etc) - // set a 2k far clip plane - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - tr.viewParms.zFar = 2048; - return; - } - - // - // set far clipping planes dynamically - // - farthestCornerDistance = 0; - for ( i = 0; i < 8; i++ ) - { - vec3_t v; - vec3_t vecTo; - float distance; - - if ( i & 1 ) - { - v[0] = tr.viewParms.visBounds[0][0]; - } - else - { - v[0] = tr.viewParms.visBounds[1][0]; - } - - if ( i & 2 ) - { - v[1] = tr.viewParms.visBounds[0][1]; - } - else - { - v[1] = tr.viewParms.visBounds[1][1]; - } - - if ( i & 4 ) - { - v[2] = tr.viewParms.visBounds[0][2]; - } - else - { - v[2] = tr.viewParms.visBounds[1][2]; - } - - VectorSubtract( v, tr.viewParms.or.origin, vecTo ); - - distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2]; - - if ( distance > farthestCornerDistance ) - { - farthestCornerDistance = distance; - } - } - tr.viewParms.zFar = sqrt( farthestCornerDistance ); -} - -/* -================= -R_SetupFrustum - -Set up the culling frustum planes for the current view using the results we got from computing the first two rows of -the projection matrix. -================= -*/ -void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float zFar, float stereoSep) -{ - vec3_t ofsorigin; - float oppleg, adjleg, length; - int i; - - if(stereoSep == 0 && xmin == -xmax) - { - // symmetric case can be simplified - VectorCopy(dest->or.origin, ofsorigin); - - length = sqrt(xmax * xmax + zProj * zProj); - oppleg = xmax / length; - adjleg = zProj / length; - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[0].normal); - VectorMA(dest->frustum[0].normal, adjleg, dest->or.axis[1], dest->frustum[0].normal); - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[1].normal); - VectorMA(dest->frustum[1].normal, -adjleg, dest->or.axis[1], dest->frustum[1].normal); - } - else - { - // In stereo rendering, due to the modification of the projection matrix, dest->or.origin is not the - // actual origin that we're rendering so offset the tip of the view pyramid. - VectorMA(dest->or.origin, stereoSep, dest->or.axis[1], ofsorigin); - - oppleg = xmax + stereoSep; - length = sqrt(oppleg * oppleg + zProj * zProj); - VectorScale(dest->or.axis[0], oppleg / length, dest->frustum[0].normal); - VectorMA(dest->frustum[0].normal, zProj / length, dest->or.axis[1], dest->frustum[0].normal); - - oppleg = xmin + stereoSep; - length = sqrt(oppleg * oppleg + zProj * zProj); - VectorScale(dest->or.axis[0], -oppleg / length, dest->frustum[1].normal); - VectorMA(dest->frustum[1].normal, -zProj / length, dest->or.axis[1], dest->frustum[1].normal); - } - - length = sqrt(ymax * ymax + zProj * zProj); - oppleg = ymax / length; - adjleg = zProj / length; - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[2].normal); - VectorMA(dest->frustum[2].normal, adjleg, dest->or.axis[2], dest->frustum[2].normal); - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[3].normal); - VectorMA(dest->frustum[3].normal, -adjleg, dest->or.axis[2], dest->frustum[3].normal); - - for (i=0 ; i<4 ; i++) { - dest->frustum[i].type = PLANE_NON_AXIAL; - dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal); - SetPlaneSignbits( &dest->frustum[i] ); - } - - if (zFar != 0.0f) - { - vec3_t farpoint; - - VectorMA(ofsorigin, zFar, dest->or.axis[0], farpoint); - VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal); - - dest->frustum[4].type = PLANE_NON_AXIAL; - dest->frustum[4].dist = DotProduct (farpoint, dest->frustum[4].normal); - SetPlaneSignbits( &dest->frustum[4] ); - dest->flags |= VPF_FARPLANEFRUSTUM; - } -} - -/* -=============== -R_SetupProjection -=============== -*/ -void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, qboolean computeFrustum) -{ - float xmin, xmax, ymin, ymax; - float width, height, stereoSep = r_stereoSeparation->value; - - /* - * offset the view origin of the viewer for stereo rendering - * by setting the projection matrix appropriately. - */ - - if(stereoSep != 0) - { - if(dest->stereoFrame == STEREO_LEFT) - stereoSep = zProj / stereoSep; - else if(dest->stereoFrame == STEREO_RIGHT) - stereoSep = zProj / -stereoSep; - else - stereoSep = 0; - } - - ymax = zProj * tan(dest->fovY * M_PI / 360.0f); - ymin = -ymax; - - xmax = zProj * tan(dest->fovX * M_PI / 360.0f); - xmin = -xmax; - - width = xmax - xmin; - height = ymax - ymin; - - dest->projectionMatrix[0] = 2 * zProj / width; - dest->projectionMatrix[4] = 0; - dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width; - dest->projectionMatrix[12] = 2 * zProj * stereoSep / width; - - dest->projectionMatrix[1] = 0; - dest->projectionMatrix[5] = 2 * zProj / height; - dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0 - dest->projectionMatrix[13] = 0; - - dest->projectionMatrix[3] = 0; - dest->projectionMatrix[7] = 0; - dest->projectionMatrix[11] = -1; - dest->projectionMatrix[15] = 0; - - // Now that we have all the data for the projection matrix we can also setup the view frustum. - if(computeFrustum) - R_SetupFrustum(dest, xmin, xmax, ymax, zProj, zFar, stereoSep); -} - -/* -=============== -R_SetupProjectionZ - -Sets the z-component transformation part in the projection matrix -=============== -*/ -void R_SetupProjectionZ(viewParms_t *dest) -{ - float zNear, zFar, depth; - - zNear = r_znear->value; - zFar = dest->zFar; - - depth = zFar - zNear; - - dest->projectionMatrix[2] = 0; - dest->projectionMatrix[6] = 0; - dest->projectionMatrix[10] = -( zFar + zNear ) / depth; - dest->projectionMatrix[14] = -2 * zFar * zNear / depth; - - if (dest->isPortal) - { - float plane[4]; - float plane2[4]; - vec4_t q, c; - - // transform portal plane into camera space - plane[0] = dest->portalPlane.normal[0]; - plane[1] = dest->portalPlane.normal[1]; - plane[2] = dest->portalPlane.normal[2]; - plane[3] = dest->portalPlane.dist; - - plane2[0] = -DotProduct (dest->or.axis[1], plane); - plane2[1] = DotProduct (dest->or.axis[2], plane); - plane2[2] = -DotProduct (dest->or.axis[0], plane); - plane2[3] = DotProduct (plane, dest->or.origin) - plane[3]; - - // Lengyel, Eric. "Modifying the Projection Matrix to Perform Oblique Near-plane Clipping". - // Terathon Software 3D Graphics Library, 2004. http://www.terathon.com/code/oblique.html - q[0] = (SGN(plane2[0]) + dest->projectionMatrix[8]) / dest->projectionMatrix[0]; - q[1] = (SGN(plane2[1]) + dest->projectionMatrix[9]) / dest->projectionMatrix[5]; - q[2] = -1.0f; - q[3] = (1.0f + dest->projectionMatrix[10]) / dest->projectionMatrix[14]; - - VectorScale4(plane2, 2.0f / DotProduct4(plane2, q), c); - - dest->projectionMatrix[2] = c[0]; - dest->projectionMatrix[6] = c[1]; - dest->projectionMatrix[10] = c[2] + 1.0f; - dest->projectionMatrix[14] = c[3]; - - } - -} - -/* -=============== -R_SetupProjectionOrtho -=============== -*/ -void R_SetupProjectionOrtho(viewParms_t *dest, vec3_t viewBounds[2]) -{ - float xmin, xmax, ymin, ymax, znear, zfar; - //viewParms_t *dest = &tr.viewParms; - int i; - vec3_t pop; - - // Quake3: Projection: - // - // Z X Y Z - // | / | / - // |/ |/ - // Y--+ +--X - - xmin = viewBounds[0][1]; - xmax = viewBounds[1][1]; - ymin = -viewBounds[1][2]; - ymax = -viewBounds[0][2]; - znear = viewBounds[0][0]; - zfar = viewBounds[1][0]; - - dest->projectionMatrix[0] = 2 / (xmax - xmin); - dest->projectionMatrix[4] = 0; - dest->projectionMatrix[8] = 0; - dest->projectionMatrix[12] = (xmax + xmin) / (xmax - xmin); - - dest->projectionMatrix[1] = 0; - dest->projectionMatrix[5] = 2 / (ymax - ymin); - dest->projectionMatrix[9] = 0; - dest->projectionMatrix[13] = (ymax + ymin) / (ymax - ymin); - - dest->projectionMatrix[2] = 0; - dest->projectionMatrix[6] = 0; - dest->projectionMatrix[10] = -2 / (zfar - znear); - dest->projectionMatrix[14] = -(zfar + znear) / (zfar - znear); - - dest->projectionMatrix[3] = 0; - dest->projectionMatrix[7] = 0; - dest->projectionMatrix[11] = 0; - dest->projectionMatrix[15] = 1; - - VectorScale(dest->or.axis[1], 1.0f, dest->frustum[0].normal); - VectorMA(dest->or.origin, viewBounds[0][1], dest->frustum[0].normal, pop); - dest->frustum[0].dist = DotProduct(pop, dest->frustum[0].normal); - - VectorScale(dest->or.axis[1], -1.0f, dest->frustum[1].normal); - VectorMA(dest->or.origin, -viewBounds[1][1], dest->frustum[1].normal, pop); - dest->frustum[1].dist = DotProduct(pop, dest->frustum[1].normal); - - VectorScale(dest->or.axis[2], 1.0f, dest->frustum[2].normal); - VectorMA(dest->or.origin, viewBounds[0][2], dest->frustum[2].normal, pop); - dest->frustum[2].dist = DotProduct(pop, dest->frustum[2].normal); - - VectorScale(dest->or.axis[2], -1.0f, dest->frustum[3].normal); - VectorMA(dest->or.origin, -viewBounds[1][2], dest->frustum[3].normal, pop); - dest->frustum[3].dist = DotProduct(pop, dest->frustum[3].normal); - - VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal); - VectorMA(dest->or.origin, -viewBounds[1][0], dest->frustum[4].normal, pop); - dest->frustum[4].dist = DotProduct(pop, dest->frustum[4].normal); - - for (i = 0; i < 5; i++) - { - dest->frustum[i].type = PLANE_NON_AXIAL; - SetPlaneSignbits (&dest->frustum[i]); - } - - dest->flags |= VPF_FARPLANEFRUSTUM; -} - -/* -================= -R_MirrorPoint -================= -*/ -void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { - int i; - vec3_t local; - vec3_t transformed; - float d; - - VectorSubtract( in, surface->origin, local ); - - VectorClear( transformed ); - for ( i = 0 ; i < 3 ; i++ ) { - d = DotProduct(local, surface->axis[i]); - VectorMA( transformed, d, camera->axis[i], transformed ); - } - - VectorAdd( transformed, camera->origin, out ); -} - -void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { - int i; - float d; - - VectorClear( out ); - for ( i = 0 ; i < 3 ; i++ ) { - d = DotProduct(in, surface->axis[i]); - VectorMA( out, d, camera->axis[i], out ); - } -} - - -/* -============= -R_PlaneForSurface -============= -*/ -void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) { - srfBspSurface_t *tri; - srfPoly_t *poly; - srfVert_t *v1, *v2, *v3; - vec4_t plane4; - - if (!surfType) { - Com_Memset (plane, 0, sizeof(*plane)); - plane->normal[0] = 1; - return; - } - switch (*surfType) { - case SF_FACE: - *plane = ((srfBspSurface_t *)surfType)->cullPlane; - return; - case SF_TRIANGLES: - tri = (srfBspSurface_t *)surfType; - v1 = tri->verts + tri->indexes[0]; - v2 = tri->verts + tri->indexes[1]; - v3 = tri->verts + tri->indexes[2]; - PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz ); - VectorCopy( plane4, plane->normal ); - plane->dist = plane4[3]; - return; - case SF_POLY: - poly = (srfPoly_t *)surfType; - PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz ); - VectorCopy( plane4, plane->normal ); - plane->dist = plane4[3]; - return; - default: - Com_Memset (plane, 0, sizeof(*plane)); - plane->normal[0] = 1; - return; - } -} - -/* -================= -R_GetPortalOrientation - -entityNum is the entity that the portal surface is a part of, which may -be moving and rotating. - -Returns qtrue if it should be mirrored -================= -*/ -qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum, - orientation_t *surface, orientation_t *camera, - vec3_t pvsOrigin, qboolean *mirror ) { - int i; - cplane_t originalPlane, plane; - trRefEntity_t *e; - float d; - vec3_t transformed; - - // create plane axis for the portal we are seeing - R_PlaneForSurface( drawSurf->surface, &originalPlane ); - - // rotate the plane if necessary - if ( entityNum != REFENTITYNUM_WORLD ) { - tr.currentEntityNum = entityNum; - tr.currentEntity = &tr.refdef.entities[entityNum]; - - // get the orientation of the entity - R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); - - // rotate the plane, but keep the non-rotated version for matching - // against the portalSurface entities - R_LocalNormalToWorld( originalPlane.normal, plane.normal ); - plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); - - // translate the original plane - originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); - } else { - plane = originalPlane; - } - - VectorCopy( plane.normal, surface->axis[0] ); - PerpendicularVector( surface->axis[1], surface->axis[0] ); - CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] ); - - // locate the portal entity closest to this plane. - // origin will be the origin of the portal, origin2 will be - // the origin of the camera - for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) { - e = &tr.refdef.entities[i]; - if ( e->e.reType != RT_PORTALSURFACE ) { - continue; - } - - d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; - if ( d > 64 || d < -64) { - continue; - } - - // get the pvsOrigin from the entity - VectorCopy( e->e.oldorigin, pvsOrigin ); - - // if the entity is just a mirror, don't use as a camera point - if ( e->e.oldorigin[0] == e->e.origin[0] && - e->e.oldorigin[1] == e->e.origin[1] && - e->e.oldorigin[2] == e->e.origin[2] ) { - VectorScale( plane.normal, plane.dist, surface->origin ); - VectorCopy( surface->origin, camera->origin ); - VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] ); - VectorCopy( surface->axis[1], camera->axis[1] ); - VectorCopy( surface->axis[2], camera->axis[2] ); - - *mirror = qtrue; - return qtrue; - } - - // project the origin onto the surface plane to get - // an origin point we can rotate around - d = DotProduct( e->e.origin, plane.normal ) - plane.dist; - VectorMA( e->e.origin, -d, surface->axis[0], surface->origin ); - - // now get the camera origin and orientation - VectorCopy( e->e.oldorigin, camera->origin ); - AxisCopy( e->e.axis, camera->axis ); - VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] ); - VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] ); - - // optionally rotate - if ( e->e.oldframe ) { - // if a speed is specified - if ( e->e.frame ) { - // continuous rotate - d = (tr.refdef.time/1000.0f) * e->e.frame; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } else { - // bobbing rotate, with skinNum being the rotation offset - d = sin( tr.refdef.time * 0.003f ); - d = e->e.skinNum + d * 4; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } - } - else if ( e->e.skinNum ) { - d = e->e.skinNum; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } - *mirror = qfalse; - return qtrue; - } - - // if we didn't locate a portal entity, don't render anything. - // We don't want to just treat it as a mirror, because without a - // portal entity the server won't have communicated a proper entity set - // in the snapshot - - // unfortunately, with local movement prediction it is easily possible - // to see a surface before the server has communicated the matching - // portal surface entity, so we don't want to print anything here... - - //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" ); - - return qfalse; -} - -static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum ) -{ - int i; - cplane_t originalPlane, plane; - trRefEntity_t *e; - float d; - - // create plane axis for the portal we are seeing - R_PlaneForSurface( drawSurf->surface, &originalPlane ); - - // rotate the plane if necessary - if ( entityNum != REFENTITYNUM_WORLD ) - { - tr.currentEntityNum = entityNum; - tr.currentEntity = &tr.refdef.entities[entityNum]; - - // get the orientation of the entity - R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); - - // rotate the plane, but keep the non-rotated version for matching - // against the portalSurface entities - R_LocalNormalToWorld( originalPlane.normal, plane.normal ); - plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); - - // translate the original plane - originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); - } - - // locate the portal entity closest to this plane. - // origin will be the origin of the portal, origin2 will be - // the origin of the camera - for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) - { - e = &tr.refdef.entities[i]; - if ( e->e.reType != RT_PORTALSURFACE ) { - continue; - } - - d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; - if ( d > 64 || d < -64) { - continue; - } - - // if the entity is just a mirror, don't use as a camera point - if ( e->e.oldorigin[0] == e->e.origin[0] && - e->e.oldorigin[1] == e->e.origin[1] && - e->e.oldorigin[2] == e->e.origin[2] ) - { - return qtrue; - } - - return qfalse; - } - return qfalse; -} - -/* -** SurfIsOffscreen -** -** Determines if a surface is completely offscreen. -*/ -static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) { - float shortest = 100000000; - int entityNum; - int numTriangles; - shader_t *shader; - int fogNum; - int dlighted; - int pshadowed; - vec4_t clip, eye; - int i; - unsigned int pointOr = 0; - unsigned int pointAnd = (unsigned int)~0; - - R_RotateForViewer(); - - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); - RB_BeginSurface( shader, fogNum, drawSurf->cubemapIndex); - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - - assert( tess.numVertexes < 128 ); - - for ( i = 0; i < tess.numVertexes; i++ ) - { - int j; - unsigned int pointFlags = 0; - - R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip ); - - for ( j = 0; j < 3; j++ ) - { - if ( clip[j] >= clip[3] ) - { - pointFlags |= (1 << (j*2)); - } - else if ( clip[j] <= -clip[3] ) - { - pointFlags |= ( 1 << (j*2+1)); - } - } - pointAnd &= pointFlags; - pointOr |= pointFlags; - } - - // trivially reject - if ( pointAnd ) - { - return qtrue; - } - - // determine if this surface is backfaced and also determine the distance - // to the nearest vertex so we can cull based on portal range. Culling - // based on vertex distance isn't 100% correct (we should be checking for - // range to the surface), but it's good enough for the types of portals - // we have in the game right now. - numTriangles = tess.numIndexes / 3; - - for ( i = 0; i < tess.numIndexes; i += 3 ) - { - vec3_t normal, tNormal; - - float len; - - VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal ); - - len = VectorLengthSquared( normal ); // lose the sqrt - if ( len < shortest ) - { - shortest = len; - } - - R_VboUnpackNormal(tNormal, tess.normal[tess.indexes[i]]); - - if ( DotProduct( normal, tNormal ) >= 0 ) - { - numTriangles--; - } - } - if ( !numTriangles ) - { - return qtrue; - } - - // mirrors can early out at this point, since we don't do a fade over distance - // with them (although we could) - if ( IsMirror( drawSurf, entityNum ) ) - { - return qfalse; - } - - if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) ) - { - return qtrue; - } - - return qfalse; -} - -/* -======================== -R_MirrorViewBySurface - -Returns qtrue if another view has been rendered -======================== -*/ -qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) { - vec4_t clipDest[128]; - viewParms_t newParms; - viewParms_t oldParms; - orientation_t surface, camera; - - // don't recursively mirror - if (tr.viewParms.isPortal) { - ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" ); - return qfalse; - } - - if ( r_noportals->integer || (r_fastsky->integer == 1) ) { - return qfalse; - } - - // trivially reject portal/mirror - if ( SurfIsOffscreen( drawSurf, clipDest ) ) { - return qfalse; - } - - // save old viewParms so we can return to it after the mirror view - oldParms = tr.viewParms; - - newParms = tr.viewParms; - newParms.isPortal = qtrue; - newParms.zFar = 0.0f; - newParms.flags &= ~VPF_FARPLANEFRUSTUM; - if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera, - newParms.pvsOrigin, &newParms.isMirror ) ) { - return qfalse; // bad portal, no portalentity - } - - if (newParms.isMirror) - newParms.flags |= VPF_NOVIEWMODEL; - - R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); - - VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal ); - newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal ); - - R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]); - R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]); - R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]); - - // OPTIMIZE: restrict the viewport on the mirrored view - - // render the mirror view - R_RenderView (&newParms); - - tr.viewParms = oldParms; - - return qtrue; -} - -/* -================= -R_SpriteFogNum - -See if a sprite is inside a fog volume -================= -*/ -int R_SpriteFogNum( trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) { - break; - } - if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -========================================================================================== - -DRAWSURF SORTING - -========================================================================================== -*/ - -/* -=============== -R_Radix -=============== -*/ -static ID_INLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest ) -{ - int count[ 256 ] = { 0 }; - int index[ 256 ]; - int i; - unsigned char *sortKey = NULL; - unsigned char *end = NULL; - - sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte; - end = sortKey + ( size * sizeof( drawSurf_t ) ); - for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) ) - ++count[ *sortKey ]; - - index[ 0 ] = 0; - - for( i = 1; i < 256; ++i ) - index[ i ] = index[ i - 1 ] + count[ i - 1 ]; - - sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte; - for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) ) - dest[ index[ *sortKey ]++ ] = source[ i ]; -} - -/* -=============== -R_RadixSort - -Radix sort with 4 byte size buckets -=============== -*/ -static void R_RadixSort( drawSurf_t *source, int size ) -{ - static drawSurf_t scratch[ MAX_DRAWSURFS ]; -#ifdef Q3_LITTLE_ENDIAN - R_Radix( 0, size, source, scratch ); - R_Radix( 1, size, scratch, source ); - R_Radix( 2, size, source, scratch ); - R_Radix( 3, size, scratch, source ); -#else - R_Radix( 3, size, source, scratch ); - R_Radix( 2, size, scratch, source ); - R_Radix( 1, size, source, scratch ); - R_Radix( 0, size, scratch, source ); -#endif //Q3_LITTLE_ENDIAN -} - -//========================================================================================== - -/* -================= -R_AddDrawSurf -================= -*/ -void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, - int fogIndex, int dlightMap, int pshadowMap, int cubemap ) { - int index; - - // instead of checking for overflow, we just mask the index - // so it wraps around - index = tr.refdef.numDrawSurfs & DRAWSURF_MASK; - // the sort data is packed into a single 32 bit value so it can be - // compared quickly during the qsorting process - tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT) - | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) - | ((int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap; - tr.refdef.drawSurfs[index].cubemapIndex = cubemap; - tr.refdef.drawSurfs[index].surface = surface; - tr.refdef.numDrawSurfs++; -} - -/* -================= -R_DecomposeSort -================= -*/ -void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, - int *fogNum, int *dlightMap, int *pshadowMap ) { - *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31; - *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ]; - *entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK; - *pshadowMap = (sort >> QSORT_PSHADOW_SHIFT ) & 1; - *dlightMap = sort & 1; -} - -/* -================= -R_SortDrawSurfs -================= -*/ -void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { - shader_t *shader; - int fogNum; - int entityNum; - int dlighted; - int pshadowed; - int i; - - //ri.Printf(PRINT_ALL, "firstDrawSurf %d numDrawSurfs %d\n", (int)(drawSurfs - tr.refdef.drawSurfs), numDrawSurfs); - - // it is possible for some views to not have any surfaces - if ( numDrawSurfs < 1 ) { - // we still need to add it for hyperspace cases - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); - return; - } - - // if we overflowed MAX_DRAWSURFS, the drawsurfs - // wrapped around in the buffer and we will be missing - // the first surfaces, not the last ones - if ( numDrawSurfs > MAX_DRAWSURFS ) { - numDrawSurfs = MAX_DRAWSURFS; - } - - // sort the drawsurfs by sort type, then orientation, then shader - R_RadixSort( drawSurfs, numDrawSurfs ); - - // skip pass through drawing if rendering a shadow map - if (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)) - { - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); - return; - } - - // check for any pass through drawing, which - // may cause another view to be rendered first - for ( i = 0 ; i < numDrawSurfs ; i++ ) { - R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); - - if ( shader->sort > SS_PORTAL ) { - break; - } - - // no shader should ever have this sort type - if ( shader->sort == SS_BAD ) { - ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name ); - } - - // if the mirror was completely clipped away, we may need to check another surface - if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) { - // this is a debug option to see exactly what is being mirrored - if ( r_portalOnly->integer ) { - return; - } - break; // only one mirror view at a time - } - } - - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); -} - -static void R_AddEntitySurface (int entityNum) -{ - trRefEntity_t *ent; - shader_t *shader; - - tr.currentEntityNum = entityNum; - - ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum]; - - ent->needDlights = qfalse; - - // preshift the value we are going to OR into the drawsurf sort - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - - // - // the weapon model must be handled special -- - // we don't want the hacked weapon position showing in - // mirrors, because the true body position will already be drawn - // - if ( (ent->e.renderfx & RF_FIRST_PERSON) && (tr.viewParms.flags & VPF_NOVIEWMODEL)) { - return; - } - - // simple generated models, like sprites and beams, are not culled - switch ( ent->e.reType ) { - case RT_PORTALSURFACE: - break; // don't draw anything - case RT_SPRITE: - case RT_BEAM: - case RT_LIGHTNING: - case RT_RAIL_CORE: - case RT_RAIL_RINGS: - // self blood sprites, talk balloons, etc should not be drawn in the primary - // view. We can't just do this check for all entities, because md3 - // entities may still want to cast shadows from them - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - return; - } - shader = R_GetShaderByHandle( ent->e.customShader ); - R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0, 0, 0 /*cubeMap*/ ); - break; - - case RT_MODEL: - // we must set up parts of tr.or for model culling - R_RotateForEntity( ent, &tr.viewParms, &tr.or ); - - tr.currentModel = R_GetModelByHandle( ent->e.hModel ); - if (!tr.currentModel) { - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 /*cubeMap*/ ); - } else { - switch ( tr.currentModel->type ) { - case MOD_MESH: - R_AddMD3Surfaces( ent ); - break; - case MOD_MDR: - R_MDRAddAnimSurfaces( ent ); - break; - case MOD_IQM: - R_AddIQMSurfaces( ent ); - break; - case MOD_BRUSH: - R_AddBrushModelSurfaces( ent ); - break; - case MOD_BAD: // null model axis - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - break; - } - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 ); - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" ); - break; - } - } - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" ); - } -} - -/* -============= -R_AddEntitySurfaces -============= -*/ -void R_AddEntitySurfaces (void) { - int i; - - if ( !r_drawentities->integer ) { - return; - } - - for ( i = 0; i < tr.refdef.num_entities; i++) - R_AddEntitySurface(i); -} - - -/* -==================== -R_GenerateDrawSurfs -==================== -*/ -void R_GenerateDrawSurfs( void ) { - R_AddWorldSurfaces (); - - R_AddPolygonSurfaces(); - - // set the projection matrix with the minimum zfar - // now that we have the world bounded - // this needs to be done before entities are - // added, because they use the projection - // matrix for lod calculation - - // dynamically compute far clip plane distance - if (!(tr.viewParms.flags & VPF_SHADOWMAP)) - { - R_SetFarClip(); - } - - // we know the size of the clipping volume. Now set the rest of the projection matrix. - R_SetupProjectionZ (&tr.viewParms); - - R_AddEntitySurfaces (); -} - -/* -================ -R_DebugPolygon -================ -*/ -void R_DebugPolygon( int color, int numPoints, float *points ) { - // FIXME: implement this -#if 0 - int i; - - GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - // draw solid shade - - qglColor3f( color&1, (color>>1)&1, (color>>2)&1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); - - // draw wireframe outline - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - qglDepthRange( 0, 0 ); - qglColor3f( 1, 1, 1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); - qglDepthRange( 0, 1 ); -#endif -} - -/* -==================== -R_DebugGraphics - -Visualization aid for movement clipping debugging -==================== -*/ -void R_DebugGraphics( void ) { - if ( !r_debugSurface->integer ) { - return; - } - - R_IssuePendingRenderCommands(); - - GL_Bind( tr.whiteImage); - GL_Cull( CT_FRONT_SIDED ); - ri.CM_DrawDebugSurface( R_DebugPolygon ); -} - - -/* -================ -R_RenderView - -A view may be either the actual camera view, -or a mirror / remote location -================ -*/ -void R_RenderView (viewParms_t *parms) { - int firstDrawSurf; - - if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) { - return; - } - - tr.viewCount++; - - tr.viewParms = *parms; - tr.viewParms.frameSceneNum = tr.frameSceneNum; - tr.viewParms.frameCount = tr.frameCount; - - firstDrawSurf = tr.refdef.numDrawSurfs; - - tr.viewCount++; - - // set viewParms.world - R_RotateForViewer (); - - R_SetupProjection(&tr.viewParms, r_zproj->value, tr.viewParms.zFar, qtrue); - - R_GenerateDrawSurfs(); - - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); - - // draw main system development information (surface outlines, etc) - R_DebugGraphics(); -} - - -void R_RenderDlightCubemaps(const refdef_t *fd) -{ - int i; - - for (i = 0; i < tr.refdef.num_dlights; i++) - { - viewParms_t shadowParms; - int j; - - // use previous frame to determine visible dlights - if ((1 << i) & tr.refdef.dlightMask) - continue; - - Com_Memset( &shadowParms, 0, sizeof( shadowParms ) ); - - shadowParms.viewportX = tr.refdef.x; - shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + PSHADOW_MAP_SIZE ); - shadowParms.viewportWidth = PSHADOW_MAP_SIZE; - shadowParms.viewportHeight = PSHADOW_MAP_SIZE; - shadowParms.isPortal = qfalse; - shadowParms.isMirror = qtrue; // because it is - - shadowParms.fovX = 90; - shadowParms.fovY = 90; - - shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL; - shadowParms.zFar = tr.refdef.dlights[i].radius; - - VectorCopy( tr.refdef.dlights[i].origin, shadowParms.or.origin ); - - for (j = 0; j < 6; j++) - { - switch(j) - { - case 0: - // -X - VectorSet( shadowParms.or.axis[0], -1, 0, 0); - VectorSet( shadowParms.or.axis[1], 0, 0, -1); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - case 1: - // +X - VectorSet( shadowParms.or.axis[0], 1, 0, 0); - VectorSet( shadowParms.or.axis[1], 0, 0, 1); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - case 2: - // -Y - VectorSet( shadowParms.or.axis[0], 0, -1, 0); - VectorSet( shadowParms.or.axis[1], 1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 0, -1); - break; - case 3: - // +Y - VectorSet( shadowParms.or.axis[0], 0, 1, 0); - VectorSet( shadowParms.or.axis[1], 1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 0, 1); - break; - case 4: - // -Z - VectorSet( shadowParms.or.axis[0], 0, 0, -1); - VectorSet( shadowParms.or.axis[1], 1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - case 5: - // +Z - VectorSet( shadowParms.or.axis[0], 0, 0, 1); - VectorSet( shadowParms.or.axis[1], -1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - } - - R_RenderView(&shadowParms); - R_AddCapShadowmapCmd( i, j ); - } - } -} - - -void R_RenderPshadowMaps(const refdef_t *fd) -{ - viewParms_t shadowParms; - int i; - - // first, make a list of shadows - for ( i = 0; i < tr.refdef.num_entities; i++) - { - trRefEntity_t *ent = &tr.refdef.entities[i]; - - if((ent->e.renderfx & (RF_FIRST_PERSON | RF_NOSHADOW))) - continue; - - //if((ent->e.renderfx & RF_THIRD_PERSON)) - //continue; - - if (ent->e.reType == RT_MODEL) - { - model_t *model = R_GetModelByHandle( ent->e.hModel ); - pshadow_t shadow; - float radius = 0.0f; - float scale = 1.0f; - vec3_t diff; - int j; - - if (!model) - continue; - - if (ent->e.nonNormalizedAxes) - { - scale = VectorLength( ent->e.axis[0] ); - } - - switch (model->type) - { - case MOD_MESH: - { - mdvFrame_t *frame = &model->mdv[0]->frames[ent->e.frame]; - - radius = frame->radius * scale; - } - break; - - case MOD_MDR: - { - // FIXME: never actually tested this - mdrHeader_t *header = model->modelData; - int frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - mdrFrame_t *frame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - - radius = frame->radius; - } - break; - case MOD_IQM: - { - // FIXME: never actually tested this - iqmData_t *data = model->modelData; - vec3_t diag; - float *framebounds; - - framebounds = data->bounds + 6*ent->e.frame; - VectorSubtract( framebounds+3, framebounds, diag ); - radius = 0.5f * VectorLength( diag ); - } - break; - - default: - break; - } - - if (!radius) - continue; - - // Cull entities that are behind the viewer by more than lightRadius - VectorSubtract(ent->e.origin, fd->vieworg, diff); - if (DotProduct(diff, fd->viewaxis[0]) < -r_pshadowDist->value) - continue; - - memset(&shadow, 0, sizeof(shadow)); - - shadow.numEntities = 1; - shadow.entityNums[0] = i; - shadow.viewRadius = radius; - shadow.lightRadius = r_pshadowDist->value; - VectorCopy(ent->e.origin, shadow.viewOrigin); - shadow.sort = DotProduct(diff, diff) / (radius * radius); - VectorCopy(ent->e.origin, shadow.entityOrigins[0]); - shadow.entityRadiuses[0] = radius; - - for (j = 0; j < MAX_CALC_PSHADOWS; j++) - { - pshadow_t swap; - - if (j + 1 > tr.refdef.num_pshadows) - { - tr.refdef.num_pshadows = j + 1; - tr.refdef.pshadows[j] = shadow; - break; - } - - // sort shadows by distance from camera divided by radius - // FIXME: sort better - if (tr.refdef.pshadows[j].sort <= shadow.sort) - continue; - - swap = tr.refdef.pshadows[j]; - tr.refdef.pshadows[j] = shadow; - shadow = swap; - } - } - } - - // next, merge touching pshadows - for ( i = 0; i < tr.refdef.num_pshadows; i++) - { - pshadow_t *ps1 = &tr.refdef.pshadows[i]; - int j; - - for (j = i + 1; j < tr.refdef.num_pshadows; j++) - { - pshadow_t *ps2 = &tr.refdef.pshadows[j]; - int k; - qboolean touch; - - if (ps1->numEntities == 8) - break; - - touch = qfalse; - if (SpheresIntersect(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius)) - { - for (k = 0; k < ps1->numEntities; k++) - { - if (SpheresIntersect(ps1->entityOrigins[k], ps1->entityRadiuses[k], ps2->viewOrigin, ps2->viewRadius)) - { - touch = qtrue; - break; - } - } - } - - if (touch) - { - vec3_t newOrigin; - float newRadius; - - BoundingSphereOfSpheres(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius, newOrigin, &newRadius); - VectorCopy(newOrigin, ps1->viewOrigin); - ps1->viewRadius = newRadius; - - ps1->entityNums[ps1->numEntities] = ps2->entityNums[0]; - VectorCopy(ps2->viewOrigin, ps1->entityOrigins[ps1->numEntities]); - ps1->entityRadiuses[ps1->numEntities] = ps2->viewRadius; - - ps1->numEntities++; - - for (k = j; k < tr.refdef.num_pshadows - 1; k++) - { - tr.refdef.pshadows[k] = tr.refdef.pshadows[k + 1]; - } - - j--; - tr.refdef.num_pshadows--; - } - } - } - - // cap number of drawn pshadows - if (tr.refdef.num_pshadows > MAX_DRAWN_PSHADOWS) - { - tr.refdef.num_pshadows = MAX_DRAWN_PSHADOWS; - } - - // next, fill up the rest of the shadow info - for ( i = 0; i < tr.refdef.num_pshadows; i++) - { - pshadow_t *shadow = &tr.refdef.pshadows[i]; - vec3_t up; - vec3_t ambientLight, directedLight, lightDir; - - VectorSet(lightDir, 0.57735f, 0.57735f, 0.57735f); -#if 1 - R_LightForPoint(shadow->viewOrigin, ambientLight, directedLight, lightDir); - - // sometimes there's no light - if (DotProduct(lightDir, lightDir) < 0.9f) - VectorSet(lightDir, 0.0f, 0.0f, 1.0f); -#endif - - if (shadow->viewRadius * 3.0f > shadow->lightRadius) - { - shadow->lightRadius = shadow->viewRadius * 3.0f; - } - - VectorMA(shadow->viewOrigin, shadow->viewRadius, lightDir, shadow->lightOrigin); - - // make up a projection, up doesn't matter - VectorScale(lightDir, -1.0f, shadow->lightViewAxis[0]); - VectorSet(up, 0, 0, -1); - - if ( abs(DotProduct(up, shadow->lightViewAxis[0])) > 0.9f ) - { - VectorSet(up, -1, 0, 0); - } - - CrossProduct(shadow->lightViewAxis[0], up, shadow->lightViewAxis[1]); - VectorNormalize(shadow->lightViewAxis[1]); - CrossProduct(shadow->lightViewAxis[0], shadow->lightViewAxis[1], shadow->lightViewAxis[2]); - - VectorCopy(shadow->lightViewAxis[0], shadow->cullPlane.normal); - shadow->cullPlane.dist = DotProduct(shadow->cullPlane.normal, shadow->lightOrigin); - shadow->cullPlane.type = PLANE_NON_AXIAL; - SetPlaneSignbits(&shadow->cullPlane); - } - - // next, render shadowmaps - for ( i = 0; i < tr.refdef.num_pshadows; i++) - { - int firstDrawSurf; - pshadow_t *shadow = &tr.refdef.pshadows[i]; - int j; - - Com_Memset( &shadowParms, 0, sizeof( shadowParms ) ); - - if (glRefConfig.framebufferObject) - { - shadowParms.viewportX = 0; - shadowParms.viewportY = 0; - } - else - { - shadowParms.viewportX = tr.refdef.x; - shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + PSHADOW_MAP_SIZE ); - } - shadowParms.viewportWidth = PSHADOW_MAP_SIZE; - shadowParms.viewportHeight = PSHADOW_MAP_SIZE; - shadowParms.isPortal = qfalse; - shadowParms.isMirror = qfalse; - - shadowParms.fovX = 90; - shadowParms.fovY = 90; - - if (glRefConfig.framebufferObject) - shadowParms.targetFbo = tr.pshadowFbos[i]; - - shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL; - shadowParms.zFar = shadow->lightRadius; - - VectorCopy(shadow->lightOrigin, shadowParms.or.origin); - - VectorCopy(shadow->lightViewAxis[0], shadowParms.or.axis[0]); - VectorCopy(shadow->lightViewAxis[1], shadowParms.or.axis[1]); - VectorCopy(shadow->lightViewAxis[2], shadowParms.or.axis[2]); - - { - tr.viewCount++; - - tr.viewParms = shadowParms; - tr.viewParms.frameSceneNum = tr.frameSceneNum; - tr.viewParms.frameCount = tr.frameCount; - - firstDrawSurf = tr.refdef.numDrawSurfs; - - tr.viewCount++; - - // set viewParms.world - R_RotateForViewer (); - - { - float xmin, xmax, ymin, ymax, znear, zfar; - viewParms_t *dest = &tr.viewParms; - vec3_t pop; - - xmin = ymin = -shadow->viewRadius; - xmax = ymax = shadow->viewRadius; - znear = 0; - zfar = shadow->lightRadius; - - dest->projectionMatrix[0] = 2 / (xmax - xmin); - dest->projectionMatrix[4] = 0; - dest->projectionMatrix[8] = (xmax + xmin) / (xmax - xmin); - dest->projectionMatrix[12] =0; - - dest->projectionMatrix[1] = 0; - dest->projectionMatrix[5] = 2 / (ymax - ymin); - dest->projectionMatrix[9] = ( ymax + ymin ) / (ymax - ymin); // normally 0 - dest->projectionMatrix[13] = 0; - - dest->projectionMatrix[2] = 0; - dest->projectionMatrix[6] = 0; - dest->projectionMatrix[10] = 2 / (zfar - znear); - dest->projectionMatrix[14] = 0; - - dest->projectionMatrix[3] = 0; - dest->projectionMatrix[7] = 0; - dest->projectionMatrix[11] = 0; - dest->projectionMatrix[15] = 1; - - VectorScale(dest->or.axis[1], 1.0f, dest->frustum[0].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[0].normal, pop); - dest->frustum[0].dist = DotProduct(pop, dest->frustum[0].normal); - - VectorScale(dest->or.axis[1], -1.0f, dest->frustum[1].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[1].normal, pop); - dest->frustum[1].dist = DotProduct(pop, dest->frustum[1].normal); - - VectorScale(dest->or.axis[2], 1.0f, dest->frustum[2].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[2].normal, pop); - dest->frustum[2].dist = DotProduct(pop, dest->frustum[2].normal); - - VectorScale(dest->or.axis[2], -1.0f, dest->frustum[3].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[3].normal, pop); - dest->frustum[3].dist = DotProduct(pop, dest->frustum[3].normal); - - VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal); - VectorMA(dest->or.origin, -shadow->lightRadius, dest->frustum[4].normal, pop); - dest->frustum[4].dist = DotProduct(pop, dest->frustum[4].normal); - - for (j = 0; j < 5; j++) - { - dest->frustum[j].type = PLANE_NON_AXIAL; - SetPlaneSignbits (&dest->frustum[j]); - } - - dest->flags |= VPF_FARPLANEFRUSTUM; - } - - for (j = 0; j < shadow->numEntities; j++) - { - R_AddEntitySurface(shadow->entityNums[j]); - } - - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); - - if (!glRefConfig.framebufferObject) - R_AddCapShadowmapCmd( i, -1 ); - } - } -} - -static float CalcSplit(float n, float f, float i, float m) -{ - return (n * pow(f / n, i / m) + (f - n) * i / m) / 2.0f; -} - - -void R_RenderSunShadowMaps(const refdef_t *fd, int level) -{ - viewParms_t shadowParms; - vec4_t lightDir, lightCol; - vec3_t lightViewAxis[3]; - vec3_t lightOrigin; - float splitZNear, splitZFar, splitBias; - float viewZNear, viewZFar; - vec3_t lightviewBounds[2]; - qboolean lightViewIndependentOfCameraView = qfalse; - - if (r_forceSun->integer == 2) - { - int scale = 32768; - float angle = (fd->time % scale) / (float)scale * M_PI; - lightDir[0] = cos(angle); - lightDir[1] = sin(35.0f * M_PI / 180.0f); - lightDir[2] = sin(angle) * cos(35.0f * M_PI / 180.0f); - lightDir[3] = 0.0f; - - if (1) //((fd->time % (scale * 2)) < scale) - { - lightCol[0] = - lightCol[1] = - lightCol[2] = CLAMP(sin(angle) * 2.0f, 0.0f, 1.0f) * 2.0f; - lightCol[3] = 1.0f; - } - else - { - lightCol[0] = - lightCol[1] = - lightCol[2] = CLAMP(sin(angle) * 2.0f * 0.1f, 0.0f, 0.1f); - lightCol[3] = 1.0f; - } - - VectorCopy4(lightDir, tr.refdef.sunDir); - VectorCopy4(lightCol, tr.refdef.sunCol); - VectorScale4(lightCol, 0.2f, tr.refdef.sunAmbCol); - } - else - { - VectorCopy4(tr.refdef.sunDir, lightDir); - } - - viewZNear = r_shadowCascadeZNear->value; - viewZFar = r_shadowCascadeZFar->value; - splitBias = r_shadowCascadeZBias->value; - - switch(level) - { - case 0: - default: - //splitZNear = r_znear->value; - //splitZFar = 256; - splitZNear = viewZNear; - splitZFar = CalcSplit(viewZNear, viewZFar, 1, 3) + splitBias; - break; - case 1: - splitZNear = CalcSplit(viewZNear, viewZFar, 1, 3) + splitBias; - splitZFar = CalcSplit(viewZNear, viewZFar, 2, 3) + splitBias; - //splitZNear = 256; - //splitZFar = 896; - break; - case 2: - splitZNear = CalcSplit(viewZNear, viewZFar, 2, 3) + splitBias; - splitZFar = viewZFar; - //splitZNear = 896; - //splitZFar = 3072; - break; - } - - VectorCopy(fd->vieworg, lightOrigin); - - - // Make up a projection - VectorScale(lightDir, -1.0f, lightViewAxis[0]); - - if (lightViewIndependentOfCameraView) - { - // Use world up as light view up - VectorSet(lightViewAxis[2], 0, 0, 1); - } - else if (level == 0) - { - // Level 0 tries to use a diamond texture orientation relative to camera view - // Use halfway between camera view forward and left for light view up - VectorAdd(fd->viewaxis[0], fd->viewaxis[1], lightViewAxis[2]); - } - else - { - // Use camera view up as light view up - VectorCopy(fd->viewaxis[2], lightViewAxis[2]); - } - - // Check if too close to parallel to light direction - if (abs(DotProduct(lightViewAxis[2], lightViewAxis[0])) > 0.9f) - { - if (lightViewIndependentOfCameraView) - { - // Use world left as light view up - VectorSet(lightViewAxis[2], 0, 1, 0); - } - else if (level == 0) - { - // Level 0 tries to use a diamond texture orientation relative to camera view - // Use halfway between camera view forward and up for light view up - VectorAdd(fd->viewaxis[0], fd->viewaxis[2], lightViewAxis[2]); - } - else - { - // Use camera view left as light view up - VectorCopy(fd->viewaxis[1], lightViewAxis[2]); - } - } - - // clean axes - CrossProduct(lightViewAxis[2], lightViewAxis[0], lightViewAxis[1]); - VectorNormalize(lightViewAxis[1]); - CrossProduct(lightViewAxis[0], lightViewAxis[1], lightViewAxis[2]); - - // Create bounds for light projection using slice of view projection - { - mat4_t lightViewMatrix; - vec4_t point, base, lightViewPoint; - float lx, ly; - - base[3] = 1; - point[3] = 1; - lightViewPoint[3] = 1; - - Mat4View(lightViewAxis, lightOrigin, lightViewMatrix); - - ClearBounds(lightviewBounds[0], lightviewBounds[1]); - - // add view near plane - lx = splitZNear * tan(fd->fov_x * M_PI / 360.0f); - ly = splitZNear * tan(fd->fov_y * M_PI / 360.0f); - VectorMA(fd->vieworg, splitZNear, fd->viewaxis[0], base); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - - // add view far plane - lx = splitZFar * tan(fd->fov_x * M_PI / 360.0f); - ly = splitZFar * tan(fd->fov_y * M_PI / 360.0f); - VectorMA(fd->vieworg, splitZFar, fd->viewaxis[0], base); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - if (!glRefConfig.depthClamp) - lightviewBounds[0][0] = lightviewBounds[1][0] - 8192; - - // Moving the Light in Texel-Sized Increments - // from http://msdn.microsoft.com/en-us/library/windows/desktop/ee416324%28v=vs.85%29.aspx - // - if (lightViewIndependentOfCameraView) - { - float cascadeBound, worldUnitsPerTexel, invWorldUnitsPerTexel; - - cascadeBound = MAX(lightviewBounds[1][0] - lightviewBounds[0][0], lightviewBounds[1][1] - lightviewBounds[0][1]); - cascadeBound = MAX(cascadeBound, lightviewBounds[1][2] - lightviewBounds[0][2]); - worldUnitsPerTexel = cascadeBound / tr.sunShadowFbo[level]->width; - invWorldUnitsPerTexel = 1.0f / worldUnitsPerTexel; - - VectorScale(lightviewBounds[0], invWorldUnitsPerTexel, lightviewBounds[0]); - lightviewBounds[0][0] = floor(lightviewBounds[0][0]); - lightviewBounds[0][1] = floor(lightviewBounds[0][1]); - lightviewBounds[0][2] = floor(lightviewBounds[0][2]); - VectorScale(lightviewBounds[0], worldUnitsPerTexel, lightviewBounds[0]); - - VectorScale(lightviewBounds[1], invWorldUnitsPerTexel, lightviewBounds[1]); - lightviewBounds[1][0] = floor(lightviewBounds[1][0]); - lightviewBounds[1][1] = floor(lightviewBounds[1][1]); - lightviewBounds[1][2] = floor(lightviewBounds[1][2]); - VectorScale(lightviewBounds[1], worldUnitsPerTexel, lightviewBounds[1]); - } - - //ri.Printf(PRINT_ALL, "znear %f zfar %f\n", lightviewBounds[0][0], lightviewBounds[1][0]); - //ri.Printf(PRINT_ALL, "fovx %f fovy %f xmin %f xmax %f ymin %f ymax %f\n", fd->fov_x, fd->fov_y, xmin, xmax, ymin, ymax); - } - - - { - int firstDrawSurf; - - Com_Memset( &shadowParms, 0, sizeof( shadowParms ) ); - - if (glRefConfig.framebufferObject) - { - shadowParms.viewportX = 0; - shadowParms.viewportY = 0; - } - else - { - shadowParms.viewportX = tr.refdef.x; - shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.sunShadowFbo[level]->height ); - } - shadowParms.viewportWidth = tr.sunShadowFbo[level]->width; - shadowParms.viewportHeight = tr.sunShadowFbo[level]->height; - shadowParms.isPortal = qfalse; - shadowParms.isMirror = qfalse; - - shadowParms.fovX = 90; - shadowParms.fovY = 90; - - if (glRefConfig.framebufferObject) - shadowParms.targetFbo = tr.sunShadowFbo[level]; - - shadowParms.flags = VPF_DEPTHSHADOW | VPF_DEPTHCLAMP | VPF_ORTHOGRAPHIC | VPF_NOVIEWMODEL; - shadowParms.zFar = lightviewBounds[1][0]; - - VectorCopy(lightOrigin, shadowParms.or.origin); - - VectorCopy(lightViewAxis[0], shadowParms.or.axis[0]); - VectorCopy(lightViewAxis[1], shadowParms.or.axis[1]); - VectorCopy(lightViewAxis[2], shadowParms.or.axis[2]); - - VectorCopy(lightOrigin, shadowParms.pvsOrigin ); - - { - tr.viewCount++; - - tr.viewParms = shadowParms; - tr.viewParms.frameSceneNum = tr.frameSceneNum; - tr.viewParms.frameCount = tr.frameCount; - - firstDrawSurf = tr.refdef.numDrawSurfs; - - tr.viewCount++; - - // set viewParms.world - R_RotateForViewer (); - - R_SetupProjectionOrtho(&tr.viewParms, lightviewBounds); - - R_AddWorldSurfaces (); - - R_AddPolygonSurfaces(); - - R_AddEntitySurfaces (); - - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); - } - - Mat4Multiply(tr.viewParms.projectionMatrix, tr.viewParms.world.modelMatrix, tr.refdef.sunShadowMvp[level]); - } -} - -void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene ) -{ - refdef_t refdef; - viewParms_t parms; - float oldColorScale = tr.refdef.colorScale; - - memset( &refdef, 0, sizeof( refdef ) ); - refdef.rdflags = 0; - VectorCopy(tr.cubemapOrigins[cubemapIndex], refdef.vieworg); - - switch(cubemapSide) - { - case 0: - // -X - VectorSet( refdef.viewaxis[0], -1, 0, 0); - VectorSet( refdef.viewaxis[1], 0, 0, -1); - VectorSet( refdef.viewaxis[2], 0, 1, 0); - break; - case 1: - // +X - VectorSet( refdef.viewaxis[0], 1, 0, 0); - VectorSet( refdef.viewaxis[1], 0, 0, 1); - VectorSet( refdef.viewaxis[2], 0, 1, 0); - break; - case 2: - // -Y - VectorSet( refdef.viewaxis[0], 0, -1, 0); - VectorSet( refdef.viewaxis[1], 1, 0, 0); - VectorSet( refdef.viewaxis[2], 0, 0, -1); - break; - case 3: - // +Y - VectorSet( refdef.viewaxis[0], 0, 1, 0); - VectorSet( refdef.viewaxis[1], 1, 0, 0); - VectorSet( refdef.viewaxis[2], 0, 0, 1); - break; - case 4: - // -Z - VectorSet( refdef.viewaxis[0], 0, 0, -1); - VectorSet( refdef.viewaxis[1], 1, 0, 0); - VectorSet( refdef.viewaxis[2], 0, 1, 0); - break; - case 5: - // +Z - VectorSet( refdef.viewaxis[0], 0, 0, 1); - VectorSet( refdef.viewaxis[1], -1, 0, 0); - VectorSet( refdef.viewaxis[2], 0, 1, 0); - break; - } - - refdef.fov_x = 90; - refdef.fov_y = 90; - - refdef.x = 0; - refdef.y = 0; - refdef.width = tr.renderCubeFbo->width; - refdef.height = tr.renderCubeFbo->height; - - refdef.time = 0; - - if (!subscene) - { - RE_BeginScene(&refdef); - - // FIXME: sun shadows aren't rendered correctly in cubemaps - // fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first - if(0) //(glRefConfig.framebufferObject && r_sunlightMode->integer && (r_forceSun->integer || tr.sunShadows)) - { - R_RenderSunShadowMaps(&refdef, 0); - R_RenderSunShadowMaps(&refdef, 1); - R_RenderSunShadowMaps(&refdef, 2); - } - } - - { - vec3_t ambient, directed, lightDir; - R_LightForPoint(tr.refdef.vieworg, ambient, directed, lightDir); - tr.refdef.colorScale = 766.0f / (directed[0] + directed[1] + directed[2] + 1.0f); - if (directed[0] + directed[1] + directed[2] == 0) - { - ri.Printf(PRINT_ALL, "cubemap %d (%f, %f, %f) is outside the lightgrid!\n", cubemapIndex, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]); - } - } - - Com_Memset( &parms, 0, sizeof( parms ) ); - - parms.viewportX = 0; - parms.viewportY = 0; - parms.viewportWidth = tr.renderCubeFbo->width; - parms.viewportHeight = tr.renderCubeFbo->height; - parms.isPortal = qfalse; - parms.isMirror = qtrue; - parms.flags = VPF_NOVIEWMODEL | VPF_NOCUBEMAPS; - - parms.fovX = 90; - parms.fovY = 90; - - VectorCopy( refdef.vieworg, parms.or.origin ); - VectorCopy( refdef.viewaxis[0], parms.or.axis[0] ); - VectorCopy( refdef.viewaxis[1], parms.or.axis[1] ); - VectorCopy( refdef.viewaxis[2], parms.or.axis[2] ); - - VectorCopy( refdef.vieworg, parms.pvsOrigin ); - - // FIXME: sun shadows aren't rendered correctly in cubemaps - // fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first - if (0) //(r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows)) - { - parms.flags = VPF_USESUNLIGHT; - } - - parms.targetFbo = tr.renderCubeFbo; - parms.targetFboLayer = cubemapSide; - parms.targetFboCubemapIndex = cubemapIndex; - - R_RenderView(&parms); - - if (subscene) - { - tr.refdef.colorScale = oldColorScale; - } - else - { - RE_EndScene(); - } -} \ No newline at end of file diff --git a/code/renderergl2/tr_marks.c b/code/renderergl2/tr_marks.c deleted file mode 100644 index 830d4d2918..0000000000 --- a/code/renderergl2/tr_marks.c +++ /dev/null @@ -1,466 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_marks.c -- polygon projection on the world polygons - -#include "tr_local.h" -//#include "assert.h" - -#define MAX_VERTS_ON_POLY 64 - -#define MARKER_OFFSET 0 // 1 - -/* -============= -R_ChopPolyBehindPlane - -Out must have space for two more vertexes than in -============= -*/ -#define SIDE_FRONT 0 -#define SIDE_BACK 1 -#define SIDE_ON 2 -static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY], - int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY], - vec3_t normal, vec_t dist, vec_t epsilon) { - float dists[MAX_VERTS_ON_POLY+4] = { 0 }; - int sides[MAX_VERTS_ON_POLY+4] = { 0 }; - int counts[3]; - float dot; - int i, j; - float *p1, *p2, *clip; - float d; - - // don't clip if it might overflow - if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) { - *numOutPoints = 0; - return; - } - - counts[0] = counts[1] = counts[2] = 0; - - // determine sides for each point - for ( i = 0 ; i < numInPoints ; i++ ) { - dot = DotProduct( inPoints[i], normal ); - dot -= dist; - dists[i] = dot; - if ( dot > epsilon ) { - sides[i] = SIDE_FRONT; - } else if ( dot < -epsilon ) { - sides[i] = SIDE_BACK; - } else { - sides[i] = SIDE_ON; - } - counts[sides[i]]++; - } - sides[i] = sides[0]; - dists[i] = dists[0]; - - *numOutPoints = 0; - - if ( !counts[0] ) { - return; - } - if ( !counts[1] ) { - *numOutPoints = numInPoints; - Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) ); - return; - } - - for ( i = 0 ; i < numInPoints ; i++ ) { - p1 = inPoints[i]; - clip = outPoints[ *numOutPoints ]; - - if ( sides[i] == SIDE_ON ) { - VectorCopy( p1, clip ); - (*numOutPoints)++; - continue; - } - - if ( sides[i] == SIDE_FRONT ) { - VectorCopy( p1, clip ); - (*numOutPoints)++; - clip = outPoints[ *numOutPoints ]; - } - - if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) { - continue; - } - - // generate a split point - p2 = inPoints[ (i+1) % numInPoints ]; - - d = dists[i] - dists[i+1]; - if ( d == 0 ) { - dot = 0; - } else { - dot = dists[i] / d; - } - - // clip xyz - - for (j=0 ; j<3 ; j++) { - clip[j] = p1[j] + dot * ( p2[j] - p1[j] ); - } - - (*numOutPoints)++; - } -} - -/* -================= -R_BoxSurfaces_r - -================= -*/ -void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) { - - int s, c; - msurface_t *surf; - int *mark; - - // do the tail recursion in a loop - while ( node->contents == -1 ) { - s = BoxOnPlaneSide( mins, maxs, node->plane ); - if (s == 1) { - node = node->children[0]; - } else if (s == 2) { - node = node->children[1]; - } else { - R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir); - node = node->children[1]; - } - } - - // add the individual surfaces - mark = tr.world->marksurfaces + node->firstmarksurface; - c = node->nummarksurfaces; - while (c--) { - int *surfViewCount; - // - if (*listlength >= listsize) break; - // - surfViewCount = &tr.world->surfacesViewCount[*mark]; - surf = tr.world->surfaces + *mark; - // check if the surface has NOIMPACT or NOMARKS set - if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) ) - || ( surf->shader->contentFlags & CONTENTS_FOG ) ) { - *surfViewCount = tr.viewCount; - } - // extra check for surfaces to avoid list overflows - else if (*(surf->data) == SF_FACE) { - // the face plane should go through the box - s = BoxOnPlaneSide( mins, maxs, &surf->cullinfo.plane ); - if (s == 1 || s == 2) { - *surfViewCount = tr.viewCount; - } else if (DotProduct(surf->cullinfo.plane.normal, dir) > -0.5) { - // don't add faces that make sharp angles with the projection direction - *surfViewCount = tr.viewCount; - } - } - else if (*(surf->data) != SF_GRID && - *(surf->data) != SF_TRIANGLES) - *surfViewCount = tr.viewCount; - // check the viewCount because the surface may have - // already been added if it spans multiple leafs - if (*surfViewCount != tr.viewCount) { - *surfViewCount = tr.viewCount; - list[*listlength] = surf->data; - (*listlength)++; - } - mark++; - } -} - -/* -================= -R_AddMarkFragments - -================= -*/ -void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY], - int numPlanes, vec3_t *normals, float *dists, - int maxPoints, vec3_t pointBuffer, - int maxFragments, markFragment_t *fragmentBuffer, - int *returnedPoints, int *returnedFragments, - vec3_t mins, vec3_t maxs) { - int pingPong, i; - markFragment_t *mf; - - // chop the surface by all the bounding planes of the to be projected polygon - pingPong = 0; - - for ( i = 0 ; i < numPlanes ; i++ ) { - - R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong], - &numClipPoints, clipPoints[!pingPong], - normals[i], dists[i], 0.5 ); - pingPong ^= 1; - if ( numClipPoints == 0 ) { - break; - } - } - // completely clipped away? - if ( numClipPoints == 0 ) { - return; - } - - // add this fragment to the returned list - if ( numClipPoints + (*returnedPoints) > maxPoints ) { - return; // not enough space for this polygon - } - /* - // all the clip points should be within the bounding box - for ( i = 0 ; i < numClipPoints ; i++ ) { - int j; - for ( j = 0 ; j < 3 ; j++ ) { - if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break; - if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break; - } - if (j < 3) break; - } - if (i < numClipPoints) return; - */ - - mf = fragmentBuffer + (*returnedFragments); - mf->firstPoint = (*returnedPoints); - mf->numPoints = numClipPoints; - Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) ); - - (*returnedPoints) += numClipPoints; - (*returnedFragments)++; -} - -/* -================= -R_MarkFragments - -================= -*/ -int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, - int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) { - int numsurfaces, numPlanes; - int i, j, k, m, n; - surfaceType_t *surfaces[64]; - vec3_t mins, maxs; - int returnedFragments; - int returnedPoints; - vec3_t normals[MAX_VERTS_ON_POLY+2]; - float dists[MAX_VERTS_ON_POLY+2]; - vec3_t clipPoints[2][MAX_VERTS_ON_POLY]; - int numClipPoints; - float *v; - srfBspSurface_t *cv; - glIndex_t *tri; - srfVert_t *dv; - vec3_t normal; - vec3_t projectionDir; - vec3_t v1, v2; - - if (numPoints <= 0) { - return 0; - } - - //increment view count for double check prevention - tr.viewCount++; - - // - VectorNormalize2( projection, projectionDir ); - // find all the brushes that are to be considered - ClearBounds( mins, maxs ); - for ( i = 0 ; i < numPoints ; i++ ) { - vec3_t temp; - - AddPointToBounds( points[i], mins, maxs ); - VectorAdd( points[i], projection, temp ); - AddPointToBounds( temp, mins, maxs ); - // make sure we get all the leafs (also the one(s) in front of the hit surface) - VectorMA( points[i], -20, projectionDir, temp ); - AddPointToBounds( temp, mins, maxs ); - } - - if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY; - // create the bounding planes for the to be projected polygon - for ( i = 0 ; i < numPoints ; i++ ) { - VectorSubtract(points[(i+1)%numPoints], points[i], v1); - VectorAdd(points[i], projection, v2); - VectorSubtract(points[i], v2, v2); - CrossProduct(v1, v2, normals[i]); - VectorNormalizeFast(normals[i]); - dists[i] = DotProduct(normals[i], points[i]); - } - // add near and far clipping planes for projection - VectorCopy(projectionDir, normals[numPoints]); - dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32; - VectorCopy(projectionDir, normals[numPoints+1]); - VectorInverse(normals[numPoints+1]); - dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20; - numPlanes = numPoints + 2; - - numsurfaces = 0; - R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir); - //assert(numsurfaces <= 64); - //assert(numsurfaces != 64); - - returnedPoints = 0; - returnedFragments = 0; - - for ( i = 0 ; i < numsurfaces ; i++ ) { - - if (*surfaces[i] == SF_GRID) { - - cv = (srfBspSurface_t *) surfaces[i]; - for ( m = 0 ; m < cv->height - 1 ; m++ ) { - for ( n = 0 ; n < cv->width - 1 ; n++ ) { - // We triangulate the grid and chop all triangles within - // the bounding planes of the to be projected polygon. - // LOD is not taken into account, not such a big deal though. - // - // It's probably much nicer to chop the grid itself and deal - // with this grid as a normal SF_GRID surface so LOD will - // be applied. However the LOD of that chopped grid must - // be synced with the LOD of the original curve. - // One way to do this; the chopped grid shares vertices with - // the original curve. When LOD is applied to the original - // curve the unused vertices are flagged. Now the chopped curve - // should skip the flagged vertices. This still leaves the - // problems with the vertices at the chopped grid edges. - // - // To avoid issues when LOD applied to "hollow curves" (like - // the ones around many jump pads) we now just add a 2 unit - // offset to the triangle vertices. - // The offset is added in the vertex normal vector direction - // so all triangles will still fit together. - // The 2 unit offset should avoid pretty much all LOD problems. - - numClipPoints = 3; - - dv = cv->verts + m * cv->width + n; - - VectorCopy(dv[0].xyz, clipPoints[0][0]); - VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]); - VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); - VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); - VectorCopy(dv[1].xyz, clipPoints[0][2]); - VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]); - // check the normal of this triangle - VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); - VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); - CrossProduct(v1, v2, normal); - VectorNormalizeFast(normal); - if (DotProduct(normal, projectionDir) < -0.1) { - // add the fragments of this triangle - R_AddMarkFragments(numClipPoints, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - - VectorCopy(dv[1].xyz, clipPoints[0][0]); - VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]); - VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); - VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); - VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]); - VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]); - // check the normal of this triangle - VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); - VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); - CrossProduct(v1, v2, normal); - VectorNormalizeFast(normal); - if (DotProduct(normal, projectionDir) < -0.05) { - // add the fragments of this triangle - R_AddMarkFragments(numClipPoints, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - } - } - } - else if (*surfaces[i] == SF_FACE) { - - srfBspSurface_t *surf = ( srfBspSurface_t * ) surfaces[i]; - - // check the normal of this face - if (DotProduct(surf->cullPlane.normal, projectionDir) > -0.5) { - continue; - } - - for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3) - { - for(j = 0; j < 3; j++) - { - v = surf->verts[tri[j]].xyz; - VectorMA(v, MARKER_OFFSET, surf->cullPlane.normal, clipPoints[0][j]); - } - - // add the fragments of this face - R_AddMarkFragments( 3 , clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - } - else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) { - - srfBspSurface_t *surf = (srfBspSurface_t *) surfaces[i]; - - for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3) - { - for(j = 0; j < 3; j++) - { - v = surf->verts[tri[j]].xyz; - VectorMA(v, MARKER_OFFSET, surf->verts[tri[j]].normal, clipPoints[0][j]); - } - - // add the fragments of this face - R_AddMarkFragments(3, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); - if(returnedFragments == maxFragments) - { - return returnedFragments; // not enough space for more fragments - } - } - } - } - return returnedFragments; -} - - - - - diff --git a/code/renderergl2/tr_mesh.c b/code/renderergl2/tr_mesh.c deleted file mode 100644 index 618958be50..0000000000 --- a/code/renderergl2/tr_mesh.c +++ /dev/null @@ -1,404 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_mesh.c: triangle model functions - -#include "tr_local.h" - -static float ProjectRadius( float r, vec3_t location ) -{ - float pr; - float dist; - float c; - vec3_t p; - float projected[4]; - - c = DotProduct( tr.viewParms.or.axis[0], tr.viewParms.or.origin ); - dist = DotProduct( tr.viewParms.or.axis[0], location ) - c; - - if ( dist <= 0 ) - return 0; - - p[0] = 0; - p[1] = fabs( r ); - p[2] = -dist; - - projected[0] = p[0] * tr.viewParms.projectionMatrix[0] + - p[1] * tr.viewParms.projectionMatrix[4] + - p[2] * tr.viewParms.projectionMatrix[8] + - tr.viewParms.projectionMatrix[12]; - - projected[1] = p[0] * tr.viewParms.projectionMatrix[1] + - p[1] * tr.viewParms.projectionMatrix[5] + - p[2] * tr.viewParms.projectionMatrix[9] + - tr.viewParms.projectionMatrix[13]; - - projected[2] = p[0] * tr.viewParms.projectionMatrix[2] + - p[1] * tr.viewParms.projectionMatrix[6] + - p[2] * tr.viewParms.projectionMatrix[10] + - tr.viewParms.projectionMatrix[14]; - - projected[3] = p[0] * tr.viewParms.projectionMatrix[3] + - p[1] * tr.viewParms.projectionMatrix[7] + - p[2] * tr.viewParms.projectionMatrix[11] + - tr.viewParms.projectionMatrix[15]; - - - pr = projected[1] / projected[3]; - - if ( pr > 1.0f ) - pr = 1.0f; - - return pr; -} - -/* -============= -R_CullModel -============= -*/ -static int R_CullModel( mdvModel_t *model, trRefEntity_t *ent ) { - vec3_t bounds[2]; - mdvFrame_t *oldFrame, *newFrame; - int i; - - // compute frame pointers - newFrame = model->frames + ent->e.frame; - oldFrame = model->frames + ent->e.oldframe; - - // cull bounding sphere ONLY if this is not an upscaled entity - if ( !ent->e.nonNormalizedAxes ) - { - if ( ent->e.frame == ent->e.oldframe ) - { - switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) - { - case CULL_OUT: - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - - case CULL_IN: - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - - case CULL_CLIP: - tr.pc.c_sphere_cull_md3_clip++; - break; - } - } - else - { - int sphereCull, sphereCullB; - - sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); - if ( newFrame == oldFrame ) { - sphereCullB = sphereCull; - } else { - sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); - } - - if ( sphereCull == sphereCullB ) - { - if ( sphereCull == CULL_OUT ) - { - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - } - else if ( sphereCull == CULL_IN ) - { - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - } - else - { - tr.pc.c_sphere_cull_md3_clip++; - } - } - } - } - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; - bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - - -/* -================= -R_ComputeLOD - -================= -*/ -int R_ComputeLOD( trRefEntity_t *ent ) { - float radius; - float flod, lodscale; - float projectedRadius; - mdvFrame_t *frame; - mdrHeader_t *mdr; - mdrFrame_t *mdrframe; - int lod; - - if ( tr.currentModel->numLods < 2 ) - { - // model has only 1 LOD level, skip computations and bias - lod = 0; - } - else - { - // multiple LODs exist, so compute projected bounding sphere - // and use that as a criteria for selecting LOD - - if(tr.currentModel->type == MOD_MDR) - { - int frameSize; - mdr = (mdrHeader_t *) tr.currentModel->modelData; - frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]); - - mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame); - - radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]); - } - else - { - //frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames ); - frame = tr.currentModel->mdv[0]->frames; - - frame += ent->e.frame; - - radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] ); - } - - if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) - { - lodscale = r_lodscale->value; - if (lodscale > 20) lodscale = 20; - flod = 1.0f - projectedRadius * lodscale; - } - else - { - // object intersects near view plane, e.g. view weapon - flod = 0; - } - - flod *= tr.currentModel->numLods; - lod = ri.ftol(flod); - - if ( lod < 0 ) - { - lod = 0; - } - else if ( lod >= tr.currentModel->numLods ) - { - lod = tr.currentModel->numLods - 1; - } - } - - lod += r_lodbias->integer; - - if ( lod >= tr.currentModel->numLods ) - lod = tr.currentModel->numLods - 1; - if ( lod < 0 ) - lod = 0; - - return lod; -} - -/* -================= -R_ComputeFogNum - -================= -*/ -int R_ComputeFogNum( mdvModel_t *model, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - mdvFrame_t *mdvFrame; - vec3_t localOrigin; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - // FIXME: non-normalized axis issues - mdvFrame = model->frames + ent->e.frame; - VectorAdd( ent->e.origin, mdvFrame->localOrigin, localOrigin ); - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - mdvFrame->radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + mdvFrame->radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -================= -R_AddMD3Surfaces - -================= -*/ -void R_AddMD3Surfaces( trRefEntity_t *ent ) { - int i; - mdvModel_t *model = NULL; - mdvSurface_t *surface = NULL; - shader_t *shader = NULL; - int cull; - int lod; - int fogNum; - int cubemapIndex; - qboolean personalModel; - - // don't add third_person objects if not in a portal - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal - || (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW))); - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) { - ent->e.frame %= tr.currentModel->mdv[0]->numFrames; - ent->e.oldframe %= tr.currentModel->mdv[0]->numFrames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ( (ent->e.frame >= tr.currentModel->mdv[0]->numFrames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= tr.currentModel->mdv[0]->numFrames) - || (ent->e.oldframe < 0) ) { - ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, - tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // compute LOD - // - lod = R_ComputeLOD( ent ); - - model = tr.currentModel->mdv[lod]; - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_CullModel ( model, ent ); - if ( cull == CULL_OUT ) { - return; - } - - // - // set up lighting now that we know we aren't culled - // - if ( !personalModel || r_shadows->integer > 1 ) { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // - // see if we are in a fog volume - // - fogNum = R_ComputeFogNum( model, ent ); - - cubemapIndex = R_CubemapForPoint(ent->e.origin); - - // - // draw all surfaces - // - surface = model->surfaces; - for ( i = 0 ; i < model->numSurfaces ; i++ ) { - - if ( ent->e.customShader ) { - shader = R_GetShaderByHandle( ent->e.customShader ); - } else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) { - skin_t *skin; - int j; - - skin = R_GetSkinByHandle( ent->e.customSkin ); - - // match the surface name to something in the skin file - shader = tr.defaultShader; - for ( j = 0 ; j < skin->numSurfaces ; j++ ) { - // the names have both been lowercased - if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) { - shader = skin->surfaces[j]->shader; - break; - } - } - if (shader == tr.defaultShader) { - ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name); - } - else if (shader->defaultShader) { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name); - } - //} else if ( surface->numShaders <= 0 ) { - //shader = tr.defaultShader; - } else { - //md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders ); - //md3Shader += ent->e.skinNum % surface->numShaders; - //shader = tr.shaders[ md3Shader->shaderIndex ]; - shader = tr.shaders[ surface->shaderIndexes[ ent->e.skinNum % surface->numShaderIndexes ] ]; - } - - // don't add third_person objects if not viewing through a portal - if(!personalModel) - { - srfVBOMDVMesh_t *vboSurface = &model->vboSurfaces[i]; - - R_AddDrawSurf((void *)vboSurface, shader, fogNum, qfalse, qfalse, cubemapIndex ); - } - - surface++; - } - -} - - - - - diff --git a/code/renderergl2/tr_model.c b/code/renderergl2/tr_model.c deleted file mode 100644 index c0dbeaa228..0000000000 --- a/code/renderergl2/tr_model.c +++ /dev/null @@ -1,1388 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_models.c -- model loading and caching - -#include "tr_local.h" - -#define LL(x) x=LittleLong(x) - -static qboolean R_LoadMD3(model_t *mod, int lod, void *buffer, int bufferSize, const char *modName); -static qboolean R_LoadMDR(model_t *mod, void *buffer, int filesize, const char *name ); - -/* -==================== -R_RegisterMD3 -==================== -*/ -qhandle_t R_RegisterMD3(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - int size; - int lod; - int ident; - qboolean loaded = qfalse; - int numLoaded; - char filename[MAX_QPATH], namebuf[MAX_QPATH+20]; - char *fext, defex[] = "md3"; - - numLoaded = 0; - - strcpy(filename, name); - - fext = strchr(filename, '.'); - if(!fext) - fext = defex; - else - { - *fext = '\0'; - fext++; - } - - for (lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod--) - { - if(lod) - Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext); - else - Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext); - - size = ri.FS_ReadFile( namebuf, &buf.v ); - if(!buf.u) - continue; - - ident = LittleLong(* (unsigned *) buf.u); - if (ident == MD3_IDENT) - loaded = R_LoadMD3(mod, lod, buf.u, size, name); - else - ri.Printf(PRINT_WARNING,"R_RegisterMD3: unknown fileid for %s\n", name); - - ri.FS_FreeFile(buf.v); - - if(loaded) - { - mod->numLods++; - numLoaded++; - } - else - break; - } - - if(numLoaded) - { - // duplicate into higher lod spots that weren't - // loaded, in case the user changes r_lodbias on the fly - for(lod--; lod >= 0; lod--) - { - mod->numLods++; - mod->mdv[lod] = mod->mdv[lod + 1]; - } - - return mod->index; - } - -#ifdef _DEBUG - ri.Printf(PRINT_WARNING,"R_RegisterMD3: couldn't load %s\n", name); -#endif - - mod->type = MOD_BAD; - return 0; -} - -/* -==================== -R_RegisterMDR -==================== -*/ -qhandle_t R_RegisterMDR(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - int ident; - qboolean loaded = qfalse; - int filesize; - - filesize = ri.FS_ReadFile(name, (void **) &buf.v); - if(!buf.u) - { - mod->type = MOD_BAD; - return 0; - } - - ident = LittleLong(*(unsigned *)buf.u); - if(ident == MDR_IDENT) - loaded = R_LoadMDR(mod, buf.u, filesize, name); - - ri.FS_FreeFile (buf.v); - - if(!loaded) - { - ri.Printf(PRINT_WARNING,"R_RegisterMDR: couldn't load mdr file %s\n", name); - mod->type = MOD_BAD; - return 0; - } - - return mod->index; -} - -/* -==================== -R_RegisterIQM -==================== -*/ -qhandle_t R_RegisterIQM(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - qboolean loaded = qfalse; - int filesize; - - filesize = ri.FS_ReadFile(name, (void **) &buf.v); - if(!buf.u) - { - mod->type = MOD_BAD; - return 0; - } - - loaded = R_LoadIQM(mod, buf.u, filesize, name); - - ri.FS_FreeFile (buf.v); - - if(!loaded) - { - ri.Printf(PRINT_WARNING,"R_RegisterIQM: couldn't load iqm file %s\n", name); - mod->type = MOD_BAD; - return 0; - } - - return mod->index; -} - - -typedef struct -{ - char *ext; - qhandle_t (*ModelLoader)( const char *, model_t * ); -} modelExtToLoaderMap_t; - -// Note that the ordering indicates the order of preference used -// when there are multiple models of different formats available -static modelExtToLoaderMap_t modelLoaders[ ] = -{ - { "iqm", R_RegisterIQM }, - { "mdr", R_RegisterMDR }, - { "md3", R_RegisterMD3 } -}; - -static int numModelLoaders = ARRAY_LEN(modelLoaders); - -//=============================================================================== - -/* -** R_GetModelByHandle -*/ -model_t *R_GetModelByHandle( qhandle_t index ) { - model_t *mod; - - // out of range gets the defualt model - if ( index < 1 || index >= tr.numModels ) { - return tr.models[0]; - } - - mod = tr.models[index]; - - return mod; -} - -//=============================================================================== - -/* -** R_AllocModel -*/ -model_t *R_AllocModel( void ) { - model_t *mod; - - if ( tr.numModels == MAX_MOD_KNOWN ) { - return NULL; - } - - mod = ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low ); - mod->index = tr.numModels; - tr.models[tr.numModels] = mod; - tr.numModels++; - - return mod; -} - -/* -==================== -RE_RegisterModel - -Loads in a model for the given name - -Zero will be returned if the model fails to load. -An entry will be retained for failed models as an -optimization to prevent disk rescanning if they are -asked for again. -==================== -*/ -qhandle_t RE_RegisterModel( const char *name ) { - model_t *mod; - qhandle_t hModel; - qboolean orgNameFailed = qfalse; - int orgLoader = -1; - int i; - char localName[ MAX_QPATH ]; - const char *ext; - char altName[ MAX_QPATH ]; - - if ( !name || !name[0] ) { - ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" ); - return 0; - } - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Model name exceeds MAX_QPATH\n" ); - return 0; - } - - // - // search the currently loaded models - // - for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) { - mod = tr.models[hModel]; - if ( !strcmp( mod->name, name ) ) { - if( mod->type == MOD_BAD ) { - return 0; - } - return hModel; - } - } - - // allocate a new model_t - - if ( ( mod = R_AllocModel() ) == NULL ) { - ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name); - return 0; - } - - // only set the name after the model has been successfully loaded - Q_strncpyz( mod->name, name, sizeof( mod->name ) ); - - - R_IssuePendingRenderCommands(); - - mod->type = MOD_BAD; - mod->numLods = 0; - - // - // load the files - // - Q_strncpyz( localName, name, MAX_QPATH ); - - ext = COM_GetExtension( localName ); - - if( *ext ) - { - // Look for the correct loader and use it - for( i = 0; i < numModelLoaders; i++ ) - { - if( !Q_stricmp( ext, modelLoaders[ i ].ext ) ) - { - // Load - hModel = modelLoaders[ i ].ModelLoader( localName, mod ); - break; - } - } - - // A loader was found - if( i < numModelLoaders ) - { - if( !hModel ) - { - // Loader failed, most likely because the file isn't there; - // try again without the extension - orgNameFailed = qtrue; - orgLoader = i; - COM_StripExtension( name, localName, MAX_QPATH ); - } - else - { - // Something loaded - return mod->index; - } - } - } - - // Try and find a suitable match using all - // the model formats supported - for( i = 0; i < numModelLoaders; i++ ) - { - if (i == orgLoader) - continue; - - Com_sprintf( altName, sizeof (altName), "%s.%s", localName, modelLoaders[ i ].ext ); - - // Load - hModel = modelLoaders[ i ].ModelLoader( altName, mod ); - - if( hModel ) - { - if( orgNameFailed ) - { - ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n", - name, altName ); - } - - break; - } - } - - return hModel; -} - -/* -================= -R_LoadMD3 -================= -*/ -static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, const char *modName) -{ - int f, i, j, k; - - md3Header_t *md3Model; - md3Frame_t *md3Frame; - md3Surface_t *md3Surf; - md3Shader_t *md3Shader; - md3Triangle_t *md3Tri; - md3St_t *md3st; - md3XyzNormal_t *md3xyz; - md3Tag_t *md3Tag; - - mdvModel_t *mdvModel; - mdvFrame_t *frame; - mdvSurface_t *surf;//, *surface; - int *shaderIndex; - glIndex_t *tri; - mdvVertex_t *v; - mdvSt_t *st; - mdvTag_t *tag; - mdvTagName_t *tagName; - - int version; - int size; - - md3Model = (md3Header_t *) buffer; - - version = LittleLong(md3Model->version); - if(version != MD3_VERSION) - { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n", modName, version, MD3_VERSION); - return qfalse; - } - - mod->type = MOD_MESH; - size = LittleLong(md3Model->ofsEnd); - mod->dataSize += size; - mdvModel = mod->mdv[lod] = ri.Hunk_Alloc(sizeof(mdvModel_t), h_low); - -// Com_Memcpy(mod->md3[lod], buffer, LittleLong(md3Model->ofsEnd)); - - LL(md3Model->ident); - LL(md3Model->version); - LL(md3Model->numFrames); - LL(md3Model->numTags); - LL(md3Model->numSurfaces); - LL(md3Model->ofsFrames); - LL(md3Model->ofsTags); - LL(md3Model->ofsSurfaces); - LL(md3Model->ofsEnd); - - if(md3Model->numFrames < 1) - { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has no frames\n", modName); - return qfalse; - } - - // swap all the frames - mdvModel->numFrames = md3Model->numFrames; - mdvModel->frames = frame = ri.Hunk_Alloc(sizeof(*frame) * md3Model->numFrames, h_low); - - md3Frame = (md3Frame_t *) ((byte *) md3Model + md3Model->ofsFrames); - for(i = 0; i < md3Model->numFrames; i++, frame++, md3Frame++) - { - frame->radius = LittleFloat(md3Frame->radius); - for(j = 0; j < 3; j++) - { - frame->bounds[0][j] = LittleFloat(md3Frame->bounds[0][j]); - frame->bounds[1][j] = LittleFloat(md3Frame->bounds[1][j]); - frame->localOrigin[j] = LittleFloat(md3Frame->localOrigin[j]); - } - } - - // swap all the tags - mdvModel->numTags = md3Model->numTags; - mdvModel->tags = tag = ri.Hunk_Alloc(sizeof(*tag) * (md3Model->numTags * md3Model->numFrames), h_low); - - md3Tag = (md3Tag_t *) ((byte *) md3Model + md3Model->ofsTags); - for(i = 0; i < md3Model->numTags * md3Model->numFrames; i++, tag++, md3Tag++) - { - for(j = 0; j < 3; j++) - { - tag->origin[j] = LittleFloat(md3Tag->origin[j]); - tag->axis[0][j] = LittleFloat(md3Tag->axis[0][j]); - tag->axis[1][j] = LittleFloat(md3Tag->axis[1][j]); - tag->axis[2][j] = LittleFloat(md3Tag->axis[2][j]); - } - } - - - mdvModel->tagNames = tagName = ri.Hunk_Alloc(sizeof(*tagName) * (md3Model->numTags), h_low); - - md3Tag = (md3Tag_t *) ((byte *) md3Model + md3Model->ofsTags); - for(i = 0; i < md3Model->numTags; i++, tagName++, md3Tag++) - { - Q_strncpyz(tagName->name, md3Tag->name, sizeof(tagName->name)); - } - - // swap all the surfaces - mdvModel->numSurfaces = md3Model->numSurfaces; - mdvModel->surfaces = surf = ri.Hunk_Alloc(sizeof(*surf) * md3Model->numSurfaces, h_low); - - md3Surf = (md3Surface_t *) ((byte *) md3Model + md3Model->ofsSurfaces); - for(i = 0; i < md3Model->numSurfaces; i++) - { - LL(md3Surf->ident); - LL(md3Surf->flags); - LL(md3Surf->numFrames); - LL(md3Surf->numShaders); - LL(md3Surf->numTriangles); - LL(md3Surf->ofsTriangles); - LL(md3Surf->numVerts); - LL(md3Surf->ofsShaders); - LL(md3Surf->ofsSt); - LL(md3Surf->ofsXyzNormals); - LL(md3Surf->ofsEnd); - - if(md3Surf->numVerts >= SHADER_MAX_VERTEXES) - { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on %s (%i).\n", - modName, SHADER_MAX_VERTEXES - 1, md3Surf->name[0] ? md3Surf->name : "a surface", - md3Surf->numVerts ); - return qfalse; - } - if(md3Surf->numTriangles * 3 >= SHADER_MAX_INDEXES) - { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on %s (%i).\n", - modName, ( SHADER_MAX_INDEXES / 3 ) - 1, md3Surf->name[0] ? md3Surf->name : "a surface", - md3Surf->numTriangles ); - return qfalse; - } - - // change to surface identifier - surf->surfaceType = SF_MDV; - - // give pointer to model for Tess_SurfaceMDX - surf->model = mdvModel; - - // copy surface name - Q_strncpyz(surf->name, md3Surf->name, sizeof(surf->name)); - - // lowercase the surface name so skin compares are faster - Q_strlwr(surf->name); - - // strip off a trailing _1 or _2 - // this is a crutch for q3data being a mess - j = strlen(surf->name); - if(j > 2 && surf->name[j - 2] == '_') - { - surf->name[j - 2] = 0; - } - - // register the shaders - surf->numShaderIndexes = md3Surf->numShaders; - surf->shaderIndexes = shaderIndex = ri.Hunk_Alloc(sizeof(*shaderIndex) * md3Surf->numShaders, h_low); - - md3Shader = (md3Shader_t *) ((byte *) md3Surf + md3Surf->ofsShaders); - for(j = 0; j < md3Surf->numShaders; j++, shaderIndex++, md3Shader++) - { - shader_t *sh; - - sh = R_FindShader(md3Shader->name, LIGHTMAP_NONE, qtrue); - if(sh->defaultShader) - { - *shaderIndex = 0; - } - else - { - *shaderIndex = sh->index; - } - } - - // swap all the triangles - surf->numIndexes = md3Surf->numTriangles * 3; - surf->indexes = tri = ri.Hunk_Alloc(sizeof(*tri) * 3 * md3Surf->numTriangles, h_low); - - md3Tri = (md3Triangle_t *) ((byte *) md3Surf + md3Surf->ofsTriangles); - for(j = 0; j < md3Surf->numTriangles; j++, tri += 3, md3Tri++) - { - tri[0] = LittleLong(md3Tri->indexes[0]); - tri[1] = LittleLong(md3Tri->indexes[1]); - tri[2] = LittleLong(md3Tri->indexes[2]); - } - - // swap all the XyzNormals - surf->numVerts = md3Surf->numVerts; - surf->verts = v = ri.Hunk_Alloc(sizeof(*v) * (md3Surf->numVerts * md3Surf->numFrames), h_low); - - md3xyz = (md3XyzNormal_t *) ((byte *) md3Surf + md3Surf->ofsXyzNormals); - for(j = 0; j < md3Surf->numVerts * md3Surf->numFrames; j++, md3xyz++, v++) - { - unsigned lat, lng; - unsigned short normal; - - v->xyz[0] = LittleShort(md3xyz->xyz[0]) * MD3_XYZ_SCALE; - v->xyz[1] = LittleShort(md3xyz->xyz[1]) * MD3_XYZ_SCALE; - v->xyz[2] = LittleShort(md3xyz->xyz[2]) * MD3_XYZ_SCALE; - - normal = LittleShort(md3xyz->normal); - - lat = ( normal >> 8 ) & 0xff; - lng = ( normal & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - v->normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - v->normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - v->normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - } - - // swap all the ST - surf->st = st = ri.Hunk_Alloc(sizeof(*st) * md3Surf->numVerts, h_low); - - md3st = (md3St_t *) ((byte *) md3Surf + md3Surf->ofsSt); - for(j = 0; j < md3Surf->numVerts; j++, md3st++, st++) - { - st->st[0] = LittleFloat(md3st->st[0]); - st->st[1] = LittleFloat(md3st->st[1]); - } - -#ifdef USE_VERT_TANGENT_SPACE - // calc tangent spaces - { - // Valgrind complaints: Conditional jump or move depends on uninitialised value(s) - // So lets Initialize them. - const float *v0 = NULL, *v1 = NULL, *v2 = NULL; - const float *t0 = NULL, *t1 = NULL, *t2 = NULL; - vec3_t tangent = { 0, 0, 0 }; - vec3_t bitangent = { 0, 0, 0 }; - vec3_t normal = { 0, 0, 0 }; - - for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++) - { - VectorClear(v->tangent); - VectorClear(v->bitangent); - if (r_recalcMD3Normals->integer) - VectorClear(v->normal); - } - - for(f = 0; f < mdvModel->numFrames; f++) - { - for(j = 0, tri = surf->indexes; j < surf->numIndexes; j += 3, tri += 3) - { - v0 = surf->verts[surf->numVerts * f + tri[0]].xyz; - v1 = surf->verts[surf->numVerts * f + tri[1]].xyz; - v2 = surf->verts[surf->numVerts * f + tri[2]].xyz; - - t0 = surf->st[tri[0]].st; - t1 = surf->st[tri[1]].st; - t2 = surf->st[tri[2]].st; - - if (!r_recalcMD3Normals->integer) - VectorCopy(v->normal, normal); - else - VectorClear(normal); - - #if 1 - R_CalcTangentSpace(tangent, bitangent, normal, v0, v1, v2, t0, t1, t2); - #else - R_CalcNormalForTriangle(normal, v0, v1, v2); - R_CalcTangentsForTriangle(tangent, bitangent, v0, v1, v2, t0, t1, t2); - #endif - - for(k = 0; k < 3; k++) - { - float *v; - - v = surf->verts[surf->numVerts * f + tri[k]].tangent; - VectorAdd(v, tangent, v); - - v = surf->verts[surf->numVerts * f + tri[k]].bitangent; - VectorAdd(v, bitangent, v); - - if (r_recalcMD3Normals->integer) - { - v = surf->verts[surf->numVerts * f + tri[k]].normal; - VectorAdd(v, normal, v); - } - } - } - } - - for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++) - { - VectorNormalize(v->tangent); - VectorNormalize(v->bitangent); - VectorNormalize(v->normal); - } - } -#endif - - // find the next surface - md3Surf = (md3Surface_t *) ((byte *) md3Surf + md3Surf->ofsEnd); - surf++; - } - - { - srfVBOMDVMesh_t *vboSurf; - - mdvModel->numVBOSurfaces = mdvModel->numSurfaces; - mdvModel->vboSurfaces = ri.Hunk_Alloc(sizeof(*mdvModel->vboSurfaces) * mdvModel->numSurfaces, h_low); - - vboSurf = mdvModel->vboSurfaces; - surf = mdvModel->surfaces; - for (i = 0; i < mdvModel->numSurfaces; i++, vboSurf++, surf++) - { - vec3_t *verts; - vec2_t *texcoords; - uint32_t *normals; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t *tangents; -#endif - - byte *data; - int dataSize; - - int ofs_xyz, ofs_normal, ofs_st; -#ifdef USE_VERT_TANGENT_SPACE - int ofs_tangent; -#endif - - dataSize = 0; - - ofs_xyz = dataSize; - dataSize += surf->numVerts * mdvModel->numFrames * sizeof(*verts); - - ofs_normal = dataSize; - dataSize += surf->numVerts * mdvModel->numFrames * sizeof(*normals); - -#ifdef USE_VERT_TANGENT_SPACE - ofs_tangent = dataSize; - dataSize += surf->numVerts * mdvModel->numFrames * sizeof(*tangents); -#endif - - ofs_st = dataSize; - dataSize += surf->numVerts * sizeof(*texcoords); - - data = ri.Malloc(dataSize); - - verts = (void *)(data + ofs_xyz); - normals = (void *)(data + ofs_normal); -#ifdef USE_VERT_TANGENT_SPACE - tangents = (void *)(data + ofs_tangent); -#endif - texcoords = (void *)(data + ofs_st); - - v = surf->verts; - for ( j = 0; j < surf->numVerts * mdvModel->numFrames ; j++, v++ ) - { - vec3_t nxt; - vec4_t tangent; - - VectorCopy(v->xyz, verts[j]); - - normals[j] = R_VboPackNormal(v->normal); -#ifdef USE_VERT_TANGENT_SPACE - CrossProduct(v->normal, v->tangent, nxt); - VectorCopy(v->tangent, tangent); - tangent[3] = (DotProduct(nxt, v->bitangent) < 0.0f) ? -1.0f : 1.0f; - - tangents[j] = R_VboPackTangent(tangent); -#endif - } - - st = surf->st; - for ( j = 0 ; j < surf->numVerts ; j++, st++ ) { - texcoords[j][0] = st->st[0]; - texcoords[j][1] = st->st[1]; - } - - vboSurf->surfaceType = SF_VBO_MDVMESH; - vboSurf->mdvModel = mdvModel; - vboSurf->mdvSurface = surf; - vboSurf->numIndexes = surf->numIndexes; - vboSurf->numVerts = surf->numVerts; - - vboSurf->minIndex = 0; - vboSurf->maxIndex = surf->numVerts; - - vboSurf->vbo = R_CreateVBO(va("staticMD3Mesh_VBO '%s'", surf->name), data, dataSize, VBO_USAGE_STATIC); - - vboSurf->vbo->ofs_xyz = ofs_xyz; - vboSurf->vbo->ofs_normal = ofs_normal; -#ifdef USE_VERT_TANGENT_SPACE - vboSurf->vbo->ofs_tangent = ofs_tangent; -#endif - vboSurf->vbo->ofs_st = ofs_st; - - vboSurf->vbo->stride_xyz = sizeof(*verts); - vboSurf->vbo->stride_normal = sizeof(*normals); -#ifdef USE_VERT_TANGENT_SPACE - vboSurf->vbo->stride_tangent = sizeof(*tangents); -#endif - vboSurf->vbo->stride_st = sizeof(*st); - - vboSurf->vbo->size_xyz = sizeof(*verts) * surf->numVerts; - vboSurf->vbo->size_normal = sizeof(*normals) * surf->numVerts; - - ri.Free(data); - - vboSurf->ibo = R_CreateIBO2(va("staticMD3Mesh_IBO %s", surf->name), surf->numIndexes, surf->indexes, VBO_USAGE_STATIC); - } - } - - return qtrue; -} - - - -/* -================= -R_LoadMDR -================= -*/ -static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name ) -{ - int i, j, k, l; - mdrHeader_t *pinmodel, *mdr; - mdrFrame_t *frame; - mdrLOD_t *lod, *curlod; - mdrSurface_t *surf, *cursurf; - mdrTriangle_t *tri, *curtri; - mdrVertex_t *v, *curv; - mdrWeight_t *weight, *curweight; - mdrTag_t *tag, *curtag; - int size; - shader_t *sh; - - pinmodel = (mdrHeader_t *)buffer; - - pinmodel->version = LittleLong(pinmodel->version); - if (pinmodel->version != MDR_VERSION) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION); - return qfalse; - } - - size = LittleLong(pinmodel->ofsEnd); - - if(size > filesize) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name); - return qfalse; - } - - mod->type = MOD_MDR; - - LL(pinmodel->numFrames); - LL(pinmodel->numBones); - LL(pinmodel->ofsFrames); - - // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame - // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target mdr. - if(pinmodel->ofsFrames < 0) - { - // mdrFrame_t is larger than mdrCompFrame_t: - size += pinmodel->numFrames * sizeof(frame->name); - // now add enough space for the uncompressed bones. - size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t))); - } - - // simple bounds check - if(pinmodel->numBones < 0 || - sizeof(*mdr) + pinmodel->numFrames * (sizeof(*frame) + (pinmodel->numBones - 1) * sizeof(*frame->bones)) > size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - mod->dataSize += size; - mod->modelData = mdr = ri.Hunk_Alloc( size, h_low ); - - // Copy all the values over from the file and fix endian issues in the process, if necessary. - - mdr->ident = LittleLong(pinmodel->ident); - mdr->version = pinmodel->version; // Don't need to swap byte order on this one, we already did above. - Q_strncpyz(mdr->name, pinmodel->name, sizeof(mdr->name)); - mdr->numFrames = pinmodel->numFrames; - mdr->numBones = pinmodel->numBones; - mdr->numLODs = LittleLong(pinmodel->numLODs); - mdr->numTags = LittleLong(pinmodel->numTags); - // We don't care about the other offset values, we'll generate them ourselves while loading. - - mod->numLods = mdr->numLODs; - - if ( mdr->numFrames < 1 ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name); - return qfalse; - } - - /* The first frame will be put into the first free space after the header */ - frame = (mdrFrame_t *)(mdr + 1); - mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr); - - if (pinmodel->ofsFrames < 0) - { - mdrCompFrame_t *cframe; - - // compressed model... - cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames); - - for(i = 0; i < mdr->numFrames; i++) - { - for(j = 0; j < 3; j++) - { - frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]); - frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]); - frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]); - } - - frame->radius = LittleFloat(cframe->radius); - frame->name[0] = '\0'; // No name supplied in the compressed version. - - for(j = 0; j < mdr->numBones; j++) - { - for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++) - { - // Do swapping for the uncompressing functions. They seem to use shorts - // values only, so I assume this will work. Never tested it on other - // platforms, though. - - ((unsigned short *)(cframe->bones[j].Comp))[k] = - LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] ); - } - - /* Now do the actual uncompressing */ - MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp); - } - - // Next Frame... - cframe = (mdrCompFrame_t *) &cframe->bones[j]; - frame = (mdrFrame_t *) &frame->bones[j]; - } - } - else - { - mdrFrame_t *curframe; - - // uncompressed model... - // - - curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames); - - // swap all the frames - for ( i = 0 ; i < mdr->numFrames ; i++) - { - for(j = 0; j < 3; j++) - { - frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]); - frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]); - frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]); - } - - frame->radius = LittleFloat(curframe->radius); - Q_strncpyz(frame->name, curframe->name, sizeof(frame->name)); - - for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++) - { - ((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] ); - } - - curframe = (mdrFrame_t *) &curframe->bones[mdr->numBones]; - frame = (mdrFrame_t *) &frame->bones[mdr->numBones]; - } - } - - // frame should now point to the first free address after all frames. - lod = (mdrLOD_t *) frame; - mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr); - - curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs)); - - // swap all the LOD's - for ( l = 0 ; l < mdr->numLODs ; l++) - { - // simple bounds check - if((byte *) (lod + 1) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - lod->numSurfaces = LittleLong(curlod->numSurfaces); - - // swap all the surfaces - surf = (mdrSurface_t *) (lod + 1); - lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod); - cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces)); - - for ( i = 0 ; i < lod->numSurfaces ; i++) - { - // simple bounds check - if((byte *) (surf + 1) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - // first do some copying stuff - - surf->ident = SF_MDR; - Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name)); - Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader)); - - surf->ofsHeader = (byte *) mdr - (byte *) surf; - - surf->numVerts = LittleLong(cursurf->numVerts); - surf->numTriangles = LittleLong(cursurf->numTriangles); - // numBoneReferences and BoneReferences generally seem to be unused - - // now do the checks that may fail. - if ( surf->numVerts >= SHADER_MAX_VERTEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", - surf->numVerts ); - return qfalse; - } - if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", - surf->numTriangles ); - return qfalse; - } - // lowercase the surface name so skin compares are faster - Q_strlwr( surf->name ); - - // register the shaders - sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue); - if ( sh->defaultShader ) { - surf->shaderIndex = 0; - } else { - surf->shaderIndex = sh->index; - } - - // now copy the vertexes. - v = (mdrVertex_t *) (surf + 1); - surf->ofsVerts = (int)((byte *) v - (byte *) surf); - curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts)); - - for(j = 0; j < surf->numVerts; j++) - { - LL(curv->numWeights); - - // simple bounds check - if(curv->numWeights < 0 || (byte *) (v + 1) + (curv->numWeights - 1) * sizeof(*weight) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - v->normal[0] = LittleFloat(curv->normal[0]); - v->normal[1] = LittleFloat(curv->normal[1]); - v->normal[2] = LittleFloat(curv->normal[2]); - - v->texCoords[0] = LittleFloat(curv->texCoords[0]); - v->texCoords[1] = LittleFloat(curv->texCoords[1]); - - v->numWeights = curv->numWeights; - weight = &v->weights[0]; - curweight = &curv->weights[0]; - - // Now copy all the weights - for(k = 0; k < v->numWeights; k++) - { - weight->boneIndex = LittleLong(curweight->boneIndex); - weight->boneWeight = LittleFloat(curweight->boneWeight); - - weight->offset[0] = LittleFloat(curweight->offset[0]); - weight->offset[1] = LittleFloat(curweight->offset[1]); - weight->offset[2] = LittleFloat(curweight->offset[2]); - - weight++; - curweight++; - } - - v = (mdrVertex_t *) weight; - curv = (mdrVertex_t *) curweight; - } - - // we know the offset to the triangles now: - tri = (mdrTriangle_t *) v; - surf->ofsTriangles = (int)((byte *) tri - (byte *) surf); - curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles)); - - // simple bounds check - if(surf->numTriangles < 0 || (byte *) (tri + surf->numTriangles) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - for(j = 0; j < surf->numTriangles; j++) - { - tri->indexes[0] = LittleLong(curtri->indexes[0]); - tri->indexes[1] = LittleLong(curtri->indexes[1]); - tri->indexes[2] = LittleLong(curtri->indexes[2]); - - tri++; - curtri++; - } - - // tri now points to the end of the surface. - surf->ofsEnd = (byte *) tri - (byte *) surf; - surf = (mdrSurface_t *) tri; - - // find the next surface. - cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd)); - } - - // surf points to the next lod now. - lod->ofsEnd = (int)((byte *) surf - (byte *) lod); - lod = (mdrLOD_t *) surf; - - // find the next LOD. - curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd)); - } - - // lod points to the first tag now, so update the offset too. - tag = (mdrTag_t *) lod; - mdr->ofsTags = (int)((byte *) tag - (byte *) mdr); - curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags)); - - // simple bounds check - if(mdr->numTags < 0 || (byte *) (tag + mdr->numTags) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - for (i = 0 ; i < mdr->numTags ; i++) - { - tag->boneIndex = LittleLong(curtag->boneIndex); - Q_strncpyz(tag->name, curtag->name, sizeof(tag->name)); - - tag++; - curtag++; - } - - // And finally we know the real offset to the end. - mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr); - - // phew! we're done. - - return qtrue; -} - - - -//============================================================================= - -/* -** RE_BeginRegistration -*/ -void RE_BeginRegistration( glconfig_t *glconfigOut ) { - - R_Init(); - - *glconfigOut = glConfig; - - R_IssuePendingRenderCommands(); - - tr.visIndex = 0; - memset(tr.visClusters, -2, sizeof(tr.visClusters)); // force markleafs to regenerate - - R_ClearFlares(); - RE_ClearScene(); - - tr.registered = qtrue; -} - -//============================================================================= - -/* -=============== -R_ModelInit -=============== -*/ -void R_ModelInit( void ) { - model_t *mod; - - // leave a space for NULL model - tr.numModels = 0; - - mod = R_AllocModel(); - mod->type = MOD_BAD; -} - - -/* -================ -R_Modellist_f -================ -*/ -void R_Modellist_f( void ) { - int i, j; - model_t *mod; - int total; - int lods; - - total = 0; - for ( i = 1 ; i < tr.numModels; i++ ) { - mod = tr.models[i]; - lods = 1; - for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) { - if ( mod->mdv[j] && mod->mdv[j] != mod->mdv[j-1] ) { - lods++; - } - } - ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name ); - total += mod->dataSize; - } - ri.Printf( PRINT_ALL, "%8i : Total models\n", total ); - -#if 0 // not working right with new hunk - if ( tr.world ) { - ri.Printf( PRINT_ALL, "\n%8i : %s\n", tr.world->dataSize, tr.world->name ); - } -#endif -} - - -//============================================================================= - - -/* -================ -R_GetTag -================ -*/ -static mdvTag_t *R_GetTag( mdvModel_t *mod, int frame, const char *_tagName ) { - int i; - mdvTag_t *tag; - mdvTagName_t *tagName; - - if ( frame >= mod->numFrames ) { - // it is possible to have a bad frame while changing models, so don't error - frame = mod->numFrames - 1; - } - - tag = mod->tags + frame * mod->numTags; - tagName = mod->tagNames; - for(i = 0; i < mod->numTags; i++, tag++, tagName++) - { - if(!strcmp(tagName->name, _tagName)) - { - return tag; - } - } - - return NULL; -} - -void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, mdvTag_t * dest) -{ - int i, j, k; - int frameSize; - mdrFrame_t *frame; - mdrTag_t *tag; - - if ( framenum >= mod->numFrames ) - { - // it is possible to have a bad frame while changing models, so don't error - framenum = mod->numFrames - 1; - } - - tag = (mdrTag_t *)((byte *)mod + mod->ofsTags); - for ( i = 0 ; i < mod->numTags ; i++, tag++ ) - { - if ( !strcmp( tag->name, tagName ) ) - { - // uncompressed model... - // - frameSize = (intptr_t)( &((mdrFrame_t *)0)->bones[ mod->numBones ] ); - frame = (mdrFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize ); - - for (j = 0; j < 3; j++) - { - for (k = 0; k < 3; k++) - dest->axis[j][k]=frame->bones[tag->boneIndex].matrix[k][j]; - } - - dest->origin[0]=frame->bones[tag->boneIndex].matrix[0][3]; - dest->origin[1]=frame->bones[tag->boneIndex].matrix[1][3]; - dest->origin[2]=frame->bones[tag->boneIndex].matrix[2][3]; - - return; - } - } - - AxisClear( dest->axis ); - VectorClear( dest->origin ); -} - -/* -================ -R_LerpTag -================ -*/ -int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, - float frac, const char *tagName ) { - mdvTag_t *start, *end; - mdvTag_t start_space, end_space; - int i; - float frontLerp, backLerp; - model_t *model; - - model = R_GetModelByHandle( handle ); - if ( !model->mdv[0] ) - { - if(model->type == MOD_MDR) - { - start = &start_space; - end = &end_space; - R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, start); - R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, end); - } - else if( model->type == MOD_IQM ) { - return R_IQMLerpTag( tag, model->modelData, - startFrame, endFrame, - frac, tagName ); - } else { - - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - - } - } - else - { - start = R_GetTag( model->mdv[0], startFrame, tagName ); - end = R_GetTag( model->mdv[0], endFrame, tagName ); - if ( !start || !end ) { - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - } - } - - frontLerp = frac; - backLerp = 1.0f - frac; - - for ( i = 0 ; i < 3 ; i++ ) { - tag->origin[i] = start->origin[i] * backLerp + end->origin[i] * frontLerp; - tag->axis[0][i] = start->axis[0][i] * backLerp + end->axis[0][i] * frontLerp; - tag->axis[1][i] = start->axis[1][i] * backLerp + end->axis[1][i] * frontLerp; - tag->axis[2][i] = start->axis[2][i] * backLerp + end->axis[2][i] * frontLerp; - } - VectorNormalize( tag->axis[0] ); - VectorNormalize( tag->axis[1] ); - VectorNormalize( tag->axis[2] ); - return qtrue; -} - - -/* -==================== -R_ModelBounds -==================== -*/ -void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { - model_t *model; - - model = R_GetModelByHandle( handle ); - - if(model->type == MOD_BRUSH) { - VectorCopy( model->bmodel->bounds[0], mins ); - VectorCopy( model->bmodel->bounds[1], maxs ); - - return; - } else if (model->type == MOD_MESH) { - mdvModel_t *header; - mdvFrame_t *frame; - - header = model->mdv[0]; - frame = header->frames; - - VectorCopy( frame->bounds[0], mins ); - VectorCopy( frame->bounds[1], maxs ); - - return; - } else if (model->type == MOD_MDR) { - mdrHeader_t *header; - mdrFrame_t *frame; - - header = (mdrHeader_t *)model->modelData; - frame = (mdrFrame_t *) ((byte *)header + header->ofsFrames); - - VectorCopy( frame->bounds[0], mins ); - VectorCopy( frame->bounds[1], maxs ); - - return; - } else if(model->type == MOD_IQM) { - iqmData_t *iqmData; - - iqmData = model->modelData; - - if(iqmData->bounds) - { - VectorCopy(iqmData->bounds, mins); - VectorCopy(iqmData->bounds + 3, maxs); - return; - } - } - - VectorClear( mins ); - VectorClear( maxs ); -} diff --git a/code/renderergl2/tr_model_iqm.c b/code/renderergl2/tr_model_iqm.c deleted file mode 100644 index b3843c5d8b..0000000000 --- a/code/renderergl2/tr_model_iqm.c +++ /dev/null @@ -1,1200 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2011 Thilo Schulz -Copyright (C) 2011 Matthias Bentrup - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -#define LL(x) x=LittleLong(x) - -// 3x4 identity matrix -static float identityMatrix[12] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0 -}; - -static qboolean IQM_CheckRange( iqmHeader_t *header, int offset, - int count,int size ) { - // return true if the range specified by offset, count and size - // doesn't fit into the file - return ( count <= 0 || - offset < 0 || - offset > header->filesize || - offset + count * size < 0 || - offset + count * size > header->filesize ); -} -// "multiply" 3x4 matrices, these are assumed to be the top 3 rows -// of a 4x4 matrix with the last row = (0 0 0 1) -static void Matrix34Multiply( float *a, float *b, float *out ) { - out[ 0] = a[0] * b[0] + a[1] * b[4] + a[ 2] * b[ 8]; - out[ 1] = a[0] * b[1] + a[1] * b[5] + a[ 2] * b[ 9]; - out[ 2] = a[0] * b[2] + a[1] * b[6] + a[ 2] * b[10]; - out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; - out[ 4] = a[4] * b[0] + a[5] * b[4] + a[ 6] * b[ 8]; - out[ 5] = a[4] * b[1] + a[5] * b[5] + a[ 6] * b[ 9]; - out[ 6] = a[4] * b[2] + a[5] * b[6] + a[ 6] * b[10]; - out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; - out[ 8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[ 8]; - out[ 9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[ 9]; - out[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10]; - out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; -} -static void Matrix34Multiply_OnlySetOrigin( float *a, float *b, float *out ) { - out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; - out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; - out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; -} -static void InterpolateMatrix( float *a, float *b, float lerp, float *mat ) { - float unLerp = 1.0f - lerp; - - mat[ 0] = a[ 0] * unLerp + b[ 0] * lerp; - mat[ 1] = a[ 1] * unLerp + b[ 1] * lerp; - mat[ 2] = a[ 2] * unLerp + b[ 2] * lerp; - mat[ 3] = a[ 3] * unLerp + b[ 3] * lerp; - mat[ 4] = a[ 4] * unLerp + b[ 4] * lerp; - mat[ 5] = a[ 5] * unLerp + b[ 5] * lerp; - mat[ 6] = a[ 6] * unLerp + b[ 6] * lerp; - mat[ 7] = a[ 7] * unLerp + b[ 7] * lerp; - mat[ 8] = a[ 8] * unLerp + b[ 8] * lerp; - mat[ 9] = a[ 9] * unLerp + b[ 9] * lerp; - mat[10] = a[10] * unLerp + b[10] * lerp; - mat[11] = a[11] * unLerp + b[11] * lerp; -} -static void JointToMatrix( vec4_t rot, vec3_t scale, vec3_t trans, - float *mat ) { - float xx = 2.0f * rot[0] * rot[0]; - float yy = 2.0f * rot[1] * rot[1]; - float zz = 2.0f * rot[2] * rot[2]; - float xy = 2.0f * rot[0] * rot[1]; - float xz = 2.0f * rot[0] * rot[2]; - float yz = 2.0f * rot[1] * rot[2]; - float wx = 2.0f * rot[3] * rot[0]; - float wy = 2.0f * rot[3] * rot[1]; - float wz = 2.0f * rot[3] * rot[2]; - - mat[ 0] = scale[0] * (1.0f - (yy + zz)); - mat[ 1] = scale[0] * (xy - wz); - mat[ 2] = scale[0] * (xz + wy); - mat[ 3] = trans[0]; - mat[ 4] = scale[1] * (xy + wz); - mat[ 5] = scale[1] * (1.0f - (xx + zz)); - mat[ 6] = scale[1] * (yz - wx); - mat[ 7] = trans[1]; - mat[ 8] = scale[2] * (xz - wy); - mat[ 9] = scale[2] * (yz + wx); - mat[10] = scale[2] * (1.0f - (xx + yy)); - mat[11] = trans[2]; -} -static void Matrix34Invert( float *inMat, float *outMat ) -{ - vec3_t trans; - float invSqrLen, *v; - - outMat[ 0] = inMat[ 0]; outMat[ 1] = inMat[ 4]; outMat[ 2] = inMat[ 8]; - outMat[ 4] = inMat[ 1]; outMat[ 5] = inMat[ 5]; outMat[ 6] = inMat[ 9]; - outMat[ 8] = inMat[ 2]; outMat[ 9] = inMat[ 6]; outMat[10] = inMat[10]; - - v = outMat + 0; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - v = outMat + 4; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - v = outMat + 8; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - - trans[0] = inMat[ 3]; - trans[1] = inMat[ 7]; - trans[2] = inMat[11]; - - outMat[ 3] = -DotProduct(outMat + 0, trans); - outMat[ 7] = -DotProduct(outMat + 4, trans); - outMat[11] = -DotProduct(outMat + 8, trans); -} - -/* -================= -R_LoadIQM - -Load an IQM model and compute the joint matrices for every frame. -================= -*/ -qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_name ) { - iqmHeader_t *header; - iqmVertexArray_t *vertexarray; - iqmTriangle_t *triangle; - iqmMesh_t *mesh; - iqmJoint_t *joint; - iqmPose_t *pose; - iqmBounds_t *bounds; - unsigned short *framedata; - char *str; - int i, j; - float jointInvMats[IQM_MAX_JOINTS * 12]; - float *mat, *matInv; - size_t size, joint_names; - iqmData_t *iqmData; - srfIQModel_t *surface; - char meshName[MAX_QPATH]; - byte blendIndexesType, blendWeightsType; - - if( filesize < sizeof(iqmHeader_t) ) { - return qfalse; - } - - header = (iqmHeader_t *)buffer; - if( Q_strncmp( header->magic, IQM_MAGIC, sizeof(header->magic) ) ) { - return qfalse; - } - - LL( header->version ); - if( header->version != IQM_VERSION ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s is a unsupported IQM version (%d), only version %d is supported.\n", - mod_name, header->version, IQM_VERSION); - return qfalse; - } - - LL( header->filesize ); - if( header->filesize > filesize || header->filesize > 16<<20 ) { - return qfalse; - } - - LL( header->flags ); - LL( header->num_text ); - LL( header->ofs_text ); - LL( header->num_meshes ); - LL( header->ofs_meshes ); - LL( header->num_vertexarrays ); - LL( header->num_vertexes ); - LL( header->ofs_vertexarrays ); - LL( header->num_triangles ); - LL( header->ofs_triangles ); - LL( header->ofs_adjacency ); - LL( header->num_joints ); - LL( header->ofs_joints ); - LL( header->num_poses ); - LL( header->ofs_poses ); - LL( header->num_anims ); - LL( header->ofs_anims ); - LL( header->num_frames ); - LL( header->num_framechannels ); - LL( header->ofs_frames ); - LL( header->ofs_bounds ); - LL( header->num_comment ); - LL( header->ofs_comment ); - LL( header->num_extensions ); - LL( header->ofs_extensions ); - - // check ioq3 joint limit - if ( header->num_joints > IQM_MAX_JOINTS ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %d joints (%d).\n", - mod_name, IQM_MAX_JOINTS, header->num_joints); - return qfalse; - } - - blendIndexesType = blendWeightsType = IQM_UBYTE; - - // check and swap vertex arrays - if( IQM_CheckRange( header, header->ofs_vertexarrays, - header->num_vertexarrays, - sizeof(iqmVertexArray_t) ) ) { - return qfalse; - } - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n, *intPtr; - - if( vertexarray->size <= 0 || vertexarray->size > 4 ) { - return qfalse; - } - - // total number of values - n = header->num_vertexes * vertexarray->size; - - switch( vertexarray->format ) { - case IQM_BYTE: - case IQM_UBYTE: - // 1 byte, no swapping necessary - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(byte) ) ) { - return qfalse; - } - break; - case IQM_INT: - case IQM_UINT: - case IQM_FLOAT: - // 4-byte swap - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(float) ) ) { - return qfalse; - } - intPtr = (int *)((byte *)header + vertexarray->offset); - for( j = 0; j < n; j++, intPtr++ ) { - LL( *intPtr ); - } - break; - default: - // not supported - return qfalse; - break; - } - - switch( vertexarray->type ) { - case IQM_POSITION: - case IQM_NORMAL: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 3 ) { - return qfalse; - } - break; - case IQM_TANGENT: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 4 ) { - return qfalse; - } - break; - case IQM_TEXCOORD: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 2 ) { - return qfalse; - } - break; - case IQM_BLENDINDEXES: - if( (vertexarray->format != IQM_INT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendIndexesType = vertexarray->format; - break; - case IQM_BLENDWEIGHTS: - if( (vertexarray->format != IQM_FLOAT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendWeightsType = vertexarray->format; - break; - case IQM_COLOR: - if( vertexarray->format != IQM_UBYTE || - vertexarray->size != 4 ) { - return qfalse; - } - break; - } - } - - // check and swap triangles - if( IQM_CheckRange( header, header->ofs_triangles, - header->num_triangles, sizeof(iqmTriangle_t) ) ) { - return qfalse; - } - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - LL( triangle->vertex[0] ); - LL( triangle->vertex[1] ); - LL( triangle->vertex[2] ); - - if( triangle->vertex[0] > header->num_vertexes || - triangle->vertex[1] > header->num_vertexes || - triangle->vertex[2] > header->num_vertexes ) { - return qfalse; - } - } - - // check and swap meshes - if( IQM_CheckRange( header, header->ofs_meshes, - header->num_meshes, sizeof(iqmMesh_t) ) ) { - return qfalse; - } - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - for( i = 0; i < header->num_meshes; i++, mesh++) { - LL( mesh->name ); - LL( mesh->material ); - LL( mesh->first_vertex ); - LL( mesh->num_vertexes ); - LL( mesh->first_triangle ); - LL( mesh->num_triangles ); - - if ( mesh->name < header->num_text ) { - Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) ); - } else { - meshName[0] = '\0'; - } - - // check ioq3 limits - if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface", - mesh->num_vertexes ); - return qfalse; - } - if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface", - mesh->num_triangles ); - return qfalse; - } - - if( mesh->first_vertex >= header->num_vertexes || - mesh->first_vertex + mesh->num_vertexes > header->num_vertexes || - mesh->first_triangle >= header->num_triangles || - mesh->first_triangle + mesh->num_triangles > header->num_triangles || - mesh->name >= header->num_text || - mesh->material >= header->num_text ) { - return qfalse; - } - } - - if( header->num_poses != header->num_joints && header->num_poses != 0 ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n", - mod_name, header->num_poses, header->num_joints ); - return qfalse; - } - - joint_names = 0; - - if ( header->num_joints ) - { - // check and swap joints - if( IQM_CheckRange( header, header->ofs_joints, - header->num_joints, sizeof(iqmJoint_t) ) ) { - return qfalse; - } - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - LL( joint->name ); - LL( joint->parent ); - LL( joint->translate[0] ); - LL( joint->translate[1] ); - LL( joint->translate[2] ); - LL( joint->rotate[0] ); - LL( joint->rotate[1] ); - LL( joint->rotate[2] ); - LL( joint->rotate[3] ); - LL( joint->scale[0] ); - LL( joint->scale[1] ); - LL( joint->scale[2] ); - - if( joint->parent < -1 || - joint->parent >= (int)header->num_joints || - joint->name >= (int)header->num_text ) { - return qfalse; - } - joint_names += strlen( (char *)header + header->ofs_text + - joint->name ) + 1; - } - } - - if ( header->num_poses ) - { - // check and swap poses - if( IQM_CheckRange( header, header->ofs_poses, - header->num_poses, sizeof(iqmPose_t) ) ) { - return qfalse; - } - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( i = 0; i < header->num_poses; i++, pose++ ) { - LL( pose->parent ); - LL( pose->mask ); - LL( pose->channeloffset[0] ); - LL( pose->channeloffset[1] ); - LL( pose->channeloffset[2] ); - LL( pose->channeloffset[3] ); - LL( pose->channeloffset[4] ); - LL( pose->channeloffset[5] ); - LL( pose->channeloffset[6] ); - LL( pose->channeloffset[7] ); - LL( pose->channeloffset[8] ); - LL( pose->channeloffset[9] ); - LL( pose->channelscale[0] ); - LL( pose->channelscale[1] ); - LL( pose->channelscale[2] ); - LL( pose->channelscale[3] ); - LL( pose->channelscale[4] ); - LL( pose->channelscale[5] ); - LL( pose->channelscale[6] ); - LL( pose->channelscale[7] ); - LL( pose->channelscale[8] ); - LL( pose->channelscale[9] ); - } - } - - if (header->ofs_bounds) - { - // check and swap model bounds - if(IQM_CheckRange(header, header->ofs_bounds, - header->num_frames, sizeof(*bounds))) - { - return qfalse; - } - bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds); - for(i = 0; i < header->num_frames; i++) - { - LL(bounds->bbmin[0]); - LL(bounds->bbmin[1]); - LL(bounds->bbmin[2]); - LL(bounds->bbmax[0]); - LL(bounds->bbmax[1]); - LL(bounds->bbmax[2]); - - bounds++; - } - } - - // allocate the model and copy the data - size = sizeof(iqmData_t); - size += header->num_meshes * sizeof( srfIQModel_t ); - size += header->num_joints * 12 * sizeof( float ); // joint mats - size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats - if(header->ofs_bounds) - size += header->num_frames * 6 * sizeof(float); // model bounds - size += header->num_vertexes * 3 * sizeof(float); // positions - size += header->num_vertexes * 2 * sizeof(float); // texcoords - size += header->num_vertexes * 3 * sizeof(float); // normals - size += header->num_vertexes * 4 * sizeof(float); // tangents - size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes - size += header->num_vertexes * 4 * sizeof(byte); // colors - size += header->num_joints * sizeof(int); // parents - size += header->num_triangles * 3 * sizeof(int); // triangles - size += joint_names; // joint names - - // blendWeights - if (blendWeightsType == IQM_FLOAT) { - size += header->num_vertexes * 4 * sizeof(float); - } else { - size += header->num_vertexes * 4 * sizeof(byte); - } - - mod->type = MOD_IQM; - iqmData = (iqmData_t *)ri.Hunk_Alloc( size, h_low ); - mod->modelData = iqmData; - - // fill header - iqmData->num_vertexes = header->num_vertexes; - iqmData->num_triangles = header->num_triangles; - iqmData->num_frames = header->num_frames; - iqmData->num_surfaces = header->num_meshes; - iqmData->num_joints = header->num_joints; - iqmData->num_poses = header->num_poses; - iqmData->blendWeightsType = blendWeightsType; - iqmData->surfaces = (srfIQModel_t *)(iqmData + 1); - iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); - iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints; - if(header->ofs_bounds) - { - iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->positions = iqmData->bounds + 6 * header->num_frames; - } - else - iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes; - iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes; - iqmData->tangents = iqmData->normals + 3 * header->num_vertexes; - iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes); - - if(blendWeightsType == IQM_FLOAT) { - iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes); - iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes); - } else { - iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes; - iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes; - } - - iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes); - iqmData->triangles = iqmData->jointParents + header->num_joints; - iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles); - - if ( header->num_joints == 0 ) - iqmData->jointMats = NULL; - - if ( header->num_poses == 0 ) - iqmData->poseMats = NULL; - - // calculate joint matrices and their inverses - // joint inverses are needed only until the pose matrices are calculated - mat = iqmData->jointMats; - matInv = jointInvMats; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - float baseFrame[12], invBaseFrame[12]; - - JointToMatrix( joint->rotate, joint->scale, joint->translate, baseFrame ); - Matrix34Invert( baseFrame, invBaseFrame ); - - if ( joint->parent >= 0 ) - { - Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat ); - mat += 12; - Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv ); - matInv += 12; - } - else - { - Com_Memcpy( mat, baseFrame, sizeof(baseFrame) ); - mat += 12; - Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) ); - matInv += 12; - } - } - - // calculate pose matrices - framedata = (unsigned short *)((byte *)header + header->ofs_frames); - mat = iqmData->poseMats; - for( i = 0; i < header->num_frames; i++ ) { - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( j = 0; j < header->num_poses; j++, pose++ ) { - vec3_t translate; - vec4_t rotate; - vec3_t scale; - float mat1[12], mat2[12]; - - translate[0] = pose->channeloffset[0]; - if( pose->mask & 0x001) - translate[0] += *framedata++ * pose->channelscale[0]; - translate[1] = pose->channeloffset[1]; - if( pose->mask & 0x002) - translate[1] += *framedata++ * pose->channelscale[1]; - translate[2] = pose->channeloffset[2]; - if( pose->mask & 0x004) - translate[2] += *framedata++ * pose->channelscale[2]; - - rotate[0] = pose->channeloffset[3]; - if( pose->mask & 0x008) - rotate[0] += *framedata++ * pose->channelscale[3]; - rotate[1] = pose->channeloffset[4]; - if( pose->mask & 0x010) - rotate[1] += *framedata++ * pose->channelscale[4]; - rotate[2] = pose->channeloffset[5]; - if( pose->mask & 0x020) - rotate[2] += *framedata++ * pose->channelscale[5]; - rotate[3] = pose->channeloffset[6]; - if( pose->mask & 0x040) - rotate[3] += *framedata++ * pose->channelscale[6]; - - scale[0] = pose->channeloffset[7]; - if( pose->mask & 0x080) - scale[0] += *framedata++ * pose->channelscale[7]; - scale[1] = pose->channeloffset[8]; - if( pose->mask & 0x100) - scale[1] += *framedata++ * pose->channelscale[8]; - scale[2] = pose->channeloffset[9]; - if( pose->mask & 0x200) - scale[2] += *framedata++ * pose->channelscale[9]; - - // construct transformation matrix - JointToMatrix( rotate, scale, translate, mat1 ); - - if( pose->parent >= 0 ) { - Matrix34Multiply( iqmData->jointMats + 12 * pose->parent, - mat1, mat2 ); - } else { - Com_Memcpy( mat2, mat1, sizeof(mat1) ); - } - - Matrix34Multiply( mat2, jointInvMats + 12 * j, mat ); - mat += 12; - } - } - - // register shaders - // overwrite the material offset with the shader index - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - surface = iqmData->surfaces; - str = (char *)header + header->ofs_text; - for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) { - surface->surfaceType = SF_IQM; - Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name)); - Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster - surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue ); - if( surface->shader->defaultShader ) - surface->shader = tr.defaultShader; - surface->data = iqmData; - surface->first_vertex = mesh->first_vertex; - surface->num_vertexes = mesh->num_vertexes; - surface->first_triangle = mesh->first_triangle; - surface->num_triangles = mesh->num_triangles; - } - - // copy vertexarrays and indexes - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n; - - // total number of values - n = header->num_vertexes * vertexarray->size; - - switch( vertexarray->type ) { - case IQM_POSITION: - Com_Memcpy( iqmData->positions, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_NORMAL: - Com_Memcpy( iqmData->normals, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TANGENT: - Com_Memcpy( iqmData->tangents, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TEXCOORD: - Com_Memcpy( iqmData->texcoords, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_BLENDINDEXES: - if( blendIndexesType == IQM_INT ) { - int *data = (int*)((byte*)header + vertexarray->offset); - for ( j = 0; j < n; j++ ) { - iqmData->blendIndexes[j] = (byte)data[j]; - } - } else { - Com_Memcpy( iqmData->blendIndexes, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - } - break; - case IQM_BLENDWEIGHTS: - if( blendWeightsType == IQM_FLOAT ) { - Com_Memcpy( iqmData->blendWeights.f, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - } else { - Com_Memcpy( iqmData->blendWeights.b, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - } - break; - case IQM_COLOR: - Com_Memcpy( iqmData->colors, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - break; - } - } - - // copy joint parents - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - iqmData->jointParents[i] = joint->parent; - } - - // copy triangles - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - iqmData->triangles[3*i+0] = triangle->vertex[0]; - iqmData->triangles[3*i+1] = triangle->vertex[1]; - iqmData->triangles[3*i+2] = triangle->vertex[2]; - } - - // copy joint names - str = iqmData->names; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - char *name = (char *)header + header->ofs_text + - joint->name; - int len = strlen( name ) + 1; - Com_Memcpy( str, name, len ); - str += len; - } - - // copy model bounds - if(header->ofs_bounds) - { - mat = iqmData->bounds; - bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds); - for(i = 0; i < header->num_frames; i++) - { - mat[0] = bounds->bbmin[0]; - mat[1] = bounds->bbmin[1]; - mat[2] = bounds->bbmin[2]; - mat[3] = bounds->bbmax[0]; - mat[4] = bounds->bbmax[1]; - mat[5] = bounds->bbmax[2]; - - mat += 6; - bounds++; - } - } - - return qtrue; -} - -/* -============= -R_CullIQM -============= -*/ -static int R_CullIQM( iqmData_t *data, trRefEntity_t *ent ) { - vec3_t bounds[2]; - vec_t *oldBounds, *newBounds; - int i; - - if (!data->bounds) { - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - } - - // compute bounds pointers - oldBounds = data->bounds + 6*ent->e.oldframe; - newBounds = data->bounds + 6*ent->e.frame; - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldBounds[i] < newBounds[i] ? oldBounds[i] : newBounds[i]; - bounds[1][i] = oldBounds[i+3] > newBounds[i+3] ? oldBounds[i+3] : newBounds[i+3]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - -/* -================= -R_ComputeIQMFogNum - -================= -*/ -int R_ComputeIQMFogNum( iqmData_t *data, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - const vec_t *bounds; - const vec_t defaultBounds[6] = { -8, -8, -8, 8, 8, 8 }; - vec3_t diag, center; - vec3_t localOrigin; - vec_t radius; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - // FIXME: non-normalized axis issues - if (data->bounds) { - bounds = data->bounds + 6*ent->e.frame; - } else { - bounds = defaultBounds; - } - VectorSubtract( bounds+3, bounds, diag ); - VectorMA( bounds, 0.5f, diag, center ); - VectorAdd( ent->e.origin, center, localOrigin ); - radius = 0.5f * VectorLength( diag ); - - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -================= -R_AddIQMSurfaces - -Add all surfaces of this model -================= -*/ -void R_AddIQMSurfaces( trRefEntity_t *ent ) { - iqmData_t *data; - srfIQModel_t *surface; - int i, j; - qboolean personalModel; - int cull; - int fogNum; - int cubemapIndex; - shader_t *shader; - skin_t *skin; - - data = tr.currentModel->modelData; - surface = data->surfaces; - - // don't add third_person objects if not in a portal - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) { - ent->e.frame %= data->num_frames; - ent->e.oldframe %= data->num_frames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ( (ent->e.frame >= data->num_frames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= data->num_frames) - || (ent->e.oldframe < 0) ) { - ri.Printf( PRINT_DEVELOPER, "R_AddIQMSurfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, - tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_CullIQM ( data, ent ); - if ( cull == CULL_OUT ) { - return; - } - - // - // set up lighting now that we know we aren't culled - // - if ( !personalModel || r_shadows->integer > 1 ) { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // - // see if we are in a fog volume - // - fogNum = R_ComputeIQMFogNum( data, ent ); - - cubemapIndex = R_CubemapForPoint(ent->e.origin); - - for ( i = 0 ; i < data->num_surfaces ; i++ ) { - if(ent->e.customShader) - shader = R_GetShaderByHandle( ent->e.customShader ); - else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) - { - skin = R_GetSkinByHandle(ent->e.customSkin); - shader = tr.defaultShader; - - for(j = 0; j < skin->numSurfaces; j++) - { - if (!strcmp(skin->surfaces[j]->name, surface->name)) - { - shader = skin->surfaces[j]->shader; - break; - } - } - } else { - shader = surface->shader; - } - - // we will add shadows even if the main object isn't visible in the view - - // stencil shadows can't do personal models unless I polyhedron clip - if ( !personalModel - && r_shadows->integer == 2 - && fogNum == 0 - && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, 0, 0, 0 ); - } - - // projection shadows work fine with personal models - if ( r_shadows->integer == 3 - && fogNum == 0 - && (ent->e.renderfx & RF_SHADOW_PLANE ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, 0, 0 ); - } - - if( !personalModel ) { - R_AddDrawSurf( (void *)surface, shader, fogNum, 0, 0, cubemapIndex ); - } - - surface++; - } -} - - -static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, - float backlerp, float *mat ) { - float *mat1, *mat2; - int *joint = data->jointParents; - int i; - - if ( data->num_poses == 0 ) { - for( i = 0; i < data->num_joints; i++, joint++ ) { - if( *joint >= 0 ) { - Matrix34Multiply( mat + 12 * *joint, - identityMatrix, mat + 12*i ); - } else { - Com_Memcpy( mat + 12*i, identityMatrix, 12 * sizeof(float) ); - } - } - return; - } - - if ( oldframe == frame ) { - mat1 = data->poseMats + 12 * data->num_poses * frame; - for( i = 0; i < data->num_poses; i++, joint++ ) { - if( *joint >= 0 ) { - Matrix34Multiply( mat + 12 * *joint, - mat1 + 12*i, mat + 12*i ); - } else { - Com_Memcpy( mat + 12*i, mat1 + 12*i, 12 * sizeof(float) ); - } - } - } else { - mat1 = data->poseMats + 12 * data->num_poses * frame; - mat2 = data->poseMats + 12 * data->num_poses * oldframe; - - for( i = 0; i < data->num_poses; i++, joint++ ) { - if( *joint >= 0 ) { - float tmpMat[12]; - InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, - backlerp, tmpMat ); - Matrix34Multiply( mat + 12 * *joint, - tmpMat, mat + 12*i ); - - } else { - InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, - backlerp, mat ); - } - } - } -} - -static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, - float backlerp, float *mat ) { - float *mat1; - int i; - - ComputePoseMats( data, frame, oldframe, backlerp, mat ); - - for( i = 0; i < data->num_joints; i++ ) { - float outmat[12]; - mat1 = mat + 12 * i; - - Com_Memcpy(outmat, mat1, sizeof(outmat)); - - Matrix34Multiply_OnlySetOrigin( outmat, data->jointMats + 12 * i, mat1 ); - } -} - - -/* -================= -RB_AddIQMSurfaces - -Compute vertices for this model surface -================= -*/ -void RB_IQMSurfaceAnim( surfaceType_t *surface ) { - srfIQModel_t *surf = (srfIQModel_t *)surface; - iqmData_t *data = surf->data; - float jointMats[IQM_MAX_JOINTS * 12]; - int i; - - vec4_t *outXYZ; - uint32_t *outNormal; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t *outTangent; -#endif - vec2_t (*outTexCoord)[2]; - vec4_t *outColor; - - int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0; - int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0; - float backlerp = backEnd.currentEntity->e.backlerp; - - int *tri; - glIndex_t *ptr; - glIndex_t base; - - RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 ); - - outXYZ = &tess.xyz[tess.numVertexes]; - outNormal = &tess.normal[tess.numVertexes]; -#ifdef USE_VERT_TANGENT_SPACE - outTangent = &tess.tangent[tess.numVertexes]; -#endif - outTexCoord = &tess.texCoords[tess.numVertexes]; - outColor = &tess.vertexColors[tess.numVertexes]; - - // compute interpolated joint matrices - if ( data->num_poses > 0 ) { - ComputePoseMats( data, frame, oldframe, backlerp, jointMats ); - } - - // transform vertexes and fill other data - for( i = 0; i < surf->num_vertexes; - i++, outXYZ++, outNormal++, outTexCoord++, outColor++ ) { - int j, k; - float vtxMat[12]; - float nrmMat[9]; - int vtx = i + surf->first_vertex; - float blendWeights[4]; - int numWeights; - - for ( numWeights = 0; numWeights < 4; numWeights++ ) { - if ( data->blendWeightsType == IQM_FLOAT ) - blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights]; - else - blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f; - - if ( blendWeights[numWeights] <= 0 ) - break; - } - - if ( data->num_poses == 0 || numWeights == 0 ) { - // no blend joint, use identity matrix. - Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) ); - } else { - // compute the vertex matrix by blending the up to - // four blend weights - Com_Memset( vtxMat, 0, 12 * sizeof (float) ); - for( j = 0; j < numWeights; j++ ) { - for( k = 0; k < 12; k++ ) { - vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k]; - } - } - } - - // compute the normal matrix as transpose of the adjoint - // of the vertex matrix - nrmMat[ 0] = vtxMat[ 5]*vtxMat[10] - vtxMat[ 6]*vtxMat[ 9]; - nrmMat[ 1] = vtxMat[ 6]*vtxMat[ 8] - vtxMat[ 4]*vtxMat[10]; - nrmMat[ 2] = vtxMat[ 4]*vtxMat[ 9] - vtxMat[ 5]*vtxMat[ 8]; - nrmMat[ 3] = vtxMat[ 2]*vtxMat[ 9] - vtxMat[ 1]*vtxMat[10]; - nrmMat[ 4] = vtxMat[ 0]*vtxMat[10] - vtxMat[ 2]*vtxMat[ 8]; - nrmMat[ 5] = vtxMat[ 1]*vtxMat[ 8] - vtxMat[ 0]*vtxMat[ 9]; - nrmMat[ 6] = vtxMat[ 1]*vtxMat[ 6] - vtxMat[ 2]*vtxMat[ 5]; - nrmMat[ 7] = vtxMat[ 2]*vtxMat[ 4] - vtxMat[ 0]*vtxMat[ 6]; - nrmMat[ 8] = vtxMat[ 0]*vtxMat[ 5] - vtxMat[ 1]*vtxMat[ 4]; - - (*outTexCoord)[0][0] = data->texcoords[2*vtx + 0]; - (*outTexCoord)[0][1] = data->texcoords[2*vtx + 1]; - (*outTexCoord)[1][0] = (*outTexCoord)[0][0]; - (*outTexCoord)[1][1] = (*outTexCoord)[0][1]; - - (*outXYZ)[0] = - vtxMat[ 0] * data->positions[3*vtx+0] + - vtxMat[ 1] * data->positions[3*vtx+1] + - vtxMat[ 2] * data->positions[3*vtx+2] + - vtxMat[ 3]; - (*outXYZ)[1] = - vtxMat[ 4] * data->positions[3*vtx+0] + - vtxMat[ 5] * data->positions[3*vtx+1] + - vtxMat[ 6] * data->positions[3*vtx+2] + - vtxMat[ 7]; - (*outXYZ)[2] = - vtxMat[ 8] * data->positions[3*vtx+0] + - vtxMat[ 9] * data->positions[3*vtx+1] + - vtxMat[10] * data->positions[3*vtx+2] + - vtxMat[11]; - (*outXYZ)[3] = 1.0f; - - { - vec3_t normal; - vec4_t tangent; - - normal[0] = DotProduct(&nrmMat[0], &data->normals[3*vtx]); - normal[1] = DotProduct(&nrmMat[3], &data->normals[3*vtx]); - normal[2] = DotProduct(&nrmMat[6], &data->normals[3*vtx]); - - *outNormal = R_VboPackNormal(normal); - -#ifdef USE_VERT_TANGENT_SPACE - tangent[0] = DotProduct(&nrmMat[0], &data->tangents[4*vtx]); - tangent[1] = DotProduct(&nrmMat[3], &data->tangents[4*vtx]); - tangent[2] = DotProduct(&nrmMat[6], &data->tangents[4*vtx]); - tangent[3] = data->tangents[4*vtx+3]; - - *outTangent++ = R_VboPackTangent(tangent); -#endif - } - - (*outColor)[0] = data->colors[4*vtx+0] / 255.0f; - (*outColor)[1] = data->colors[4*vtx+1] / 255.0f; - (*outColor)[2] = data->colors[4*vtx+2] / 255.0f; - (*outColor)[3] = data->colors[4*vtx+3] / 255.0f; - } - - tri = data->triangles + 3 * surf->first_triangle; - ptr = &tess.indexes[tess.numIndexes]; - base = tess.numVertexes; - - for( i = 0; i < surf->num_triangles; i++ ) { - *ptr++ = base + (*tri++ - surf->first_vertex); - *ptr++ = base + (*tri++ - surf->first_vertex); - *ptr++ = base + (*tri++ - surf->first_vertex); - } - - tess.numIndexes += 3 * surf->num_triangles; - tess.numVertexes += surf->num_vertexes; -} - -int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, - int startFrame, int endFrame, - float frac, const char *tagName ) { - float jointMats[IQM_MAX_JOINTS * 12]; - int joint; - char *names = data->names; - - // get joint number by reading the joint names - for( joint = 0; joint < data->num_joints; joint++ ) { - if( !strcmp( tagName, names ) ) - break; - names += strlen( names ) + 1; - } - if( joint >= data->num_joints ) { - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - } - - ComputeJointMats( data, startFrame, endFrame, frac, jointMats ); - - tag->axis[0][0] = jointMats[12 * joint + 0]; - tag->axis[1][0] = jointMats[12 * joint + 1]; - tag->axis[2][0] = jointMats[12 * joint + 2]; - tag->origin[0] = jointMats[12 * joint + 3]; - tag->axis[0][1] = jointMats[12 * joint + 4]; - tag->axis[1][1] = jointMats[12 * joint + 5]; - tag->axis[2][1] = jointMats[12 * joint + 6]; - tag->origin[1] = jointMats[12 * joint + 7]; - tag->axis[0][2] = jointMats[12 * joint + 8]; - tag->axis[1][2] = jointMats[12 * joint + 9]; - tag->axis[2][2] = jointMats[12 * joint + 10]; - tag->origin[2] = jointMats[12 * joint + 11]; - - return qtrue; -} diff --git a/code/renderergl2/tr_postprocess.c b/code/renderergl2/tr_postprocess.c deleted file mode 100644 index 35982fcec9..0000000000 --- a/code/renderergl2/tr_postprocess.c +++ /dev/null @@ -1,523 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2011 Andrei Drexler, Richard Allen, James Canete - -This file is part of Reaction source code. - -Reaction source code 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. - -Reaction source code 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 Reaction source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -void RB_ToneMap(FBO_t *hdrFbo, ivec4_t hdrBox, FBO_t *ldrFbo, ivec4_t ldrBox, int autoExposure) -{ - ivec4_t srcBox, dstBox; - vec4_t color; - static int lastFrameCount = 0; - - if (autoExposure) - { - if (lastFrameCount == 0 || tr.frameCount < lastFrameCount || tr.frameCount - lastFrameCount > 5) - { - // determine average log luminance - FBO_t *srcFbo, *dstFbo, *tmp; - int size = 256; - - lastFrameCount = tr.frameCount; - - VectorSet4(dstBox, 0, 0, size, size); - - FBO_Blit(hdrFbo, hdrBox, NULL, tr.textureScratchFbo[0], dstBox, &tr.calclevels4xShader[0], NULL, 0); - - srcFbo = tr.textureScratchFbo[0]; - dstFbo = tr.textureScratchFbo[1]; - - // downscale to 1x1 texture - while (size > 1) - { - VectorSet4(srcBox, 0, 0, size, size); - //size >>= 2; - size >>= 1; - VectorSet4(dstBox, 0, 0, size, size); - - if (size == 1) - dstFbo = tr.targetLevelsFbo; - - //FBO_Blit(targetFbo, srcBox, NULL, tr.textureScratchFbo[nextScratch], dstBox, &tr.calclevels4xShader[1], NULL, 0); - FBO_FastBlit(srcFbo, srcBox, dstFbo, dstBox, GL_COLOR_BUFFER_BIT, GL_LINEAR); - - tmp = srcFbo; - srcFbo = dstFbo; - dstFbo = tmp; - } - } - - // blend with old log luminance for gradual change - VectorSet4(srcBox, 0, 0, 0, 0); - - color[0] = - color[1] = - color[2] = 1.0f; - if (glRefConfig.textureFloat) - color[3] = 0.03f; - else - color[3] = 0.1f; - - FBO_Blit(tr.targetLevelsFbo, srcBox, NULL, tr.calcLevelsFbo, NULL, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); - } - - // tonemap - color[0] = - color[1] = - color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value); - color[3] = 1.0f; - - if (autoExposure) - GL_BindToTMU(tr.calcLevelsImage, TB_LEVELSMAP); - else - GL_BindToTMU(tr.fixedLevelsImage, TB_LEVELSMAP); - - FBO_Blit(hdrFbo, hdrBox, NULL, ldrFbo, ldrBox, &tr.tonemapShader, color, 0); -} - -/* -============= -RB_BokehBlur - - -Blurs a part of one framebuffer to another. - -Framebuffers can be identical. -============= -*/ -void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float blur) -{ -// ivec4_t srcBox, dstBox; - vec4_t color; - - blur *= 10.0f; - - if (blur < 0.004f) - return; - - if (glRefConfig.framebufferObject) - { - // bokeh blur - if (blur > 0.0f) - { - ivec4_t quarterBox; - - quarterBox[0] = 0; - quarterBox[1] = tr.quarterFbo[0]->height; - quarterBox[2] = tr.quarterFbo[0]->width; - quarterBox[3] = -tr.quarterFbo[0]->height; - - // create a quarter texture - //FBO_Blit(NULL, NULL, NULL, tr.quarterFbo[0], NULL, NULL, NULL, 0); - FBO_FastBlit(src, srcBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR); - } - -#ifndef HQ_BLUR - if (blur > 1.0f) - { - // create a 1/16th texture - //FBO_Blit(tr.quarterFbo[0], NULL, NULL, tr.textureScratchFbo[0], NULL, NULL, NULL, 0); - FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); - } -#endif - - if (blur > 0.0f && blur <= 1.0f) - { - // Crossfade original with quarter texture - VectorSet4(color, 1, 1, 1, blur); - - FBO_Blit(tr.quarterFbo[0], NULL, NULL, dst, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); - } -#ifndef HQ_BLUR - // ok blur, but can see some pixelization - else if (blur > 1.0f && blur <= 2.0f) - { - // crossfade quarter texture with 1/16th texture - FBO_Blit(tr.quarterFbo[0], NULL, NULL, dst, dstBox, NULL, NULL, 0); - - VectorSet4(color, 1, 1, 1, blur - 1.0f); - - FBO_Blit(tr.textureScratchFbo[0], NULL, NULL, dst, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); - } - else if (blur > 2.0f) - { - // blur 1/16th texture then replace - int i; - - for (i = 0; i < 2; i++) - { - vec2_t blurTexScale; - float subblur; - - subblur = ((blur - 2.0f) / 2.0f) / 3.0f * (float)(i + 1); - - blurTexScale[0] = - blurTexScale[1] = subblur; - - color[0] = - color[1] = - color[2] = 0.5f; - color[3] = 1.0f; - - if (i != 0) - FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); - else - FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, 0); - } - - FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0); - } -#else // higher quality blur, but slower - else if (blur > 1.0f) - { - // blur quarter texture then replace - int i; - - src = tr.quarterFbo[0]; - dst = tr.quarterFbo[1]; - - VectorSet4(color, 0.5f, 0.5f, 0.5f, 1); - - for (i = 0; i < 2; i++) - { - vec2_t blurTexScale; - float subblur; - - subblur = (blur - 1.0f) / 2.0f * (float)(i + 1); - - blurTexScale[0] = - blurTexScale[1] = subblur; - - color[0] = - color[1] = - color[2] = 1.0f; - if (i != 0) - color[3] = 1.0f; - else - color[3] = 0.5f; - - FBO_Blit(tr.quarterFbo[0], NULL, blurTexScale, tr.quarterFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); - } - - FBO_Blit(tr.quarterFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0); - } -#endif - } -} - - -static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha) -{ - ivec4_t srcBox, dstBox; - vec4_t color; - const float inc = 1.f / passes; - const float mul = powf(stretch, inc); - float scale; - - { - vec2_t texScale; - - texScale[0] = - texScale[1] = 1.0f; - - alpha *= inc; - VectorSet4(color, alpha, alpha, alpha, 1.0f); - - VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height); - VectorSet4(dstBox, x, y, w, h); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0); - - --passes; - scale = mul; - while (passes > 0) - { - float iscale = 1.f / scale; - float s0 = xcenter * (1.f - iscale); - float t0 = (1.0f - ycenter) * (1.f - iscale); - float s1 = iscale + s0; - float t1 = iscale + t0; - - if (srcFbo) - { - srcBox[0] = s0 * srcFbo->width; - srcBox[1] = t0 * srcFbo->height; - srcBox[2] = (s1 - s0) * srcFbo->width; - srcBox[3] = (t1 - t0) * srcFbo->height; - } - else - { - srcBox[0] = s0 * glConfig.vidWidth; - srcBox[1] = t0 * glConfig.vidHeight; - srcBox[2] = (s1 - s0) * glConfig.vidWidth; - srcBox[3] = (t1 - t0) * glConfig.vidHeight; - } - - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - scale *= mul; - --passes; - } - } -} - - -static qboolean RB_UpdateSunFlareVis(void) -{ - GLuint sampleCount = 0; - if (!glRefConfig.occlusionQuery) - return qtrue; - - tr.sunFlareQueryIndex ^= 1; - if (!tr.sunFlareQueryActive[tr.sunFlareQueryIndex]) - return qtrue; - - /* debug code */ - if (0) - { - int iter; - for (iter=0 ; ; ++iter) - { - GLint available = 0; - qglGetQueryObjectivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - if (available) - break; - } - - ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter); - } - - qglGetQueryObjectuivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_ARB, &sampleCount); - return sampleCount > 0; -} - -void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox) -{ - vec4_t color; - float dot; - const float cutoff = 0.25f; - qboolean colorize = qtrue; - -// float w, h, w2, h2; - mat4_t mvp; - vec4_t pos, hpos; - - dot = DotProduct(tr.sunDirection, backEnd.viewParms.or.axis[0]); - if (dot < cutoff) - return; - - if (!RB_UpdateSunFlareVis()) - return; - - // From RB_DrawSun() - { - float dist; - mat4_t trans, model, mvp; - - Mat4Translation( backEnd.viewParms.or.origin, trans ); - Mat4Multiply( backEnd.viewParms.world.modelMatrix, trans, model ); - Mat4Multiply(backEnd.viewParms.projectionMatrix, model, mvp); - - dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - - VectorScale( tr.sunDirection, dist, pos ); - } - - // project sun point - //Mat4Multiply(backEnd.viewParms.projectionMatrix, backEnd.viewParms.world.modelMatrix, mvp); - Mat4Transform(mvp, pos, hpos); - - // transform to UV coords - hpos[3] = 0.5f / hpos[3]; - - pos[0] = 0.5f + hpos[0] * hpos[3]; - pos[1] = 0.5f + hpos[1] * hpos[3]; - - // initialize quarter buffers - { - float mul = 1.f; - vec2_t texScale; - ivec4_t rayBox, quarterBox; - - texScale[0] = - texScale[1] = 1.0f; - - VectorSet4(color, mul, mul, mul, 1); - - if (srcFbo) - { - rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / srcFbo->width; - rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / srcFbo->height; - rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / srcFbo->width; - rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / srcFbo->height; - } - else - { - rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / glConfig.vidWidth; - rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / glConfig.vidHeight; - rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / glConfig.vidWidth; - rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / glConfig.vidHeight; - } - - quarterBox[0] = 0; - quarterBox[1] = tr.quarterFbo[0]->height; - quarterBox[2] = tr.quarterFbo[0]->width; - quarterBox[3] = -tr.quarterFbo[0]->height; - - // first, downsample the framebuffer - if (colorize) - { - FBO_FastBlit(srcFbo, srcBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR); - FBO_Blit(tr.sunRaysFbo, rayBox, NULL, tr.quarterFbo[0], quarterBox, NULL, color, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); - } - else - { - FBO_FastBlit(tr.sunRaysFbo, rayBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR); - } - } - - // radial blur passes, ping-ponging between the two quarter-size buffers - { - const float stretch_add = 2.f/3.f; - float stretch = 1.f + stretch_add; - int i; - for (i=0; i<2; ++i) - { - RB_RadialBlur(tr.quarterFbo[i&1], tr.quarterFbo[(~i) & 1], 5, stretch, 0.f, 0.f, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height, pos[0], pos[1], 1.125f); - stretch += stretch_add; - } - } - - // add result back on top of the main buffer - { - float mul = 1.f; - vec2_t texScale; - - texScale[0] = - texScale[1] = 1.0f; - - VectorSet4(color, mul, mul, mul, 1); - - FBO_Blit(tr.quarterFbo[0], NULL, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); - } -} - -static void RB_BlurAxis(FBO_t *srcFbo, FBO_t *dstFbo, float strength, qboolean horizontal) -{ - float dx, dy; - float xmul, ymul; - float weights[3] = { - 0.227027027f, - 0.316216216f, - 0.070270270f, - }; - float offsets[3] = { - 0.f, - 1.3846153846f, - 3.2307692308f, - }; - - xmul = horizontal; - ymul = 1.f - xmul; - - xmul *= strength; - ymul *= strength; - - { - ivec4_t srcBox, dstBox; - vec4_t color; - vec2_t texScale; - - texScale[0] = - texScale[1] = 1.0f; - - VectorSet4(color, weights[0], weights[0], weights[0], 1.0f); - VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height); - VectorSet4(dstBox, 0, 0, dstFbo->width, dstFbo->height); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0 ); - - VectorSet4(color, weights[1], weights[1], weights[1], 1.0f); - dx = offsets[1] * xmul; - dy = offsets[1] * ymul; - VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - VectorSet4(color, weights[2], weights[2], weights[2], 1.0f); - dx = offsets[2] * xmul; - dy = offsets[2] * ymul; - VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - } -} - -static void RB_HBlur(FBO_t *srcFbo, FBO_t *dstFbo, float strength) -{ - RB_BlurAxis(srcFbo, dstFbo, strength, qtrue); -} - -static void RB_VBlur(FBO_t *srcFbo, FBO_t *dstFbo, float strength) -{ - RB_BlurAxis(srcFbo, dstFbo, strength, qfalse); -} - -void RB_GaussianBlur(float blur) -{ - //float mul = 1.f; - float factor = Com_Clamp(0.f, 1.f, blur); - - if (factor <= 0.f) - return; - - { - ivec4_t srcBox, dstBox; - vec4_t color; - vec2_t texScale; - - texScale[0] = - texScale[1] = 1.0f; - - VectorSet4(color, 1, 1, 1, 1); - - // first, downsample the framebuffer - FBO_FastBlit(NULL, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); - FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); - - // set the alpha channel - VectorSet4(srcBox, 0, 0, tr.whiteImage->width, tr.whiteImage->height); - VectorSet4(dstBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height); - qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - FBO_BlitFromTexture(tr.whiteImage, srcBox, texScale, tr.textureScratchFbo[0], dstBox, &tr.textureColorShader, color, GLS_DEPTHTEST_DISABLE); - qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - // blur the tiny buffer horizontally and vertically - RB_HBlur(tr.textureScratchFbo[0], tr.textureScratchFbo[1], factor); - RB_VBlur(tr.textureScratchFbo[1], tr.textureScratchFbo[0], factor); - - // finally, merge back to framebuffer - VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height); - VectorSet4(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight); - color[3] = factor; - FBO_Blit(tr.textureScratchFbo[0], srcBox, texScale, NULL, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); - } -} diff --git a/code/renderergl2/tr_postprocess.h b/code/renderergl2/tr_postprocess.h deleted file mode 100644 index 09daf13465..0000000000 --- a/code/renderergl2/tr_postprocess.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2011 Andrei Drexler, Richard Allen, James Canete - -This file is part of Reaction source code. - -Reaction source code 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. - -Reaction source code 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 Reaction source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#ifndef TR_POSTPROCESS_H -#define TR_POSTPROCESS_H - -#include "tr_fbo.h" - -void RB_ToneMap(FBO_t *hdrFbo, ivec4_t hdrBox, FBO_t *ldrFbo, ivec4_t ldrBox, int autoExposure); -void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float blur); -void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox); -void RB_GaussianBlur(float blur); - -#endif diff --git a/code/renderergl2/tr_scene.c b/code/renderergl2/tr_scene.c deleted file mode 100644 index db2d138670..0000000000 --- a/code/renderergl2/tr_scene.c +++ /dev/null @@ -1,559 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -int r_firstSceneDrawSurf; - -int r_numdlights; -int r_firstSceneDlight; - -int r_numentities; -int r_firstSceneEntity; - -int r_numpolys; -int r_firstScenePoly; - -int r_numpolyverts; - - -/* -==================== -R_InitNextFrame - -==================== -*/ -void R_InitNextFrame( void ) { - backEndData->commands.used = 0; - - r_firstSceneDrawSurf = 0; - - r_numdlights = 0; - r_firstSceneDlight = 0; - - r_numentities = 0; - r_firstSceneEntity = 0; - - r_numpolys = 0; - r_firstScenePoly = 0; - - r_numpolyverts = 0; -} - - -/* -==================== -RE_ClearScene - -==================== -*/ -void RE_ClearScene( void ) { - r_firstSceneDlight = r_numdlights; - r_firstSceneEntity = r_numentities; - r_firstScenePoly = r_numpolys; -} - -/* -=========================================================================== - -DISCRETE POLYS - -=========================================================================== -*/ - -/* -===================== -R_AddPolygonSurfaces - -Adds all the scene's polys into this view's drawsurf list -===================== -*/ -void R_AddPolygonSurfaces( void ) { - int i; - shader_t *sh; - srfPoly_t *poly; - int fogMask; - - tr.currentEntityNum = REFENTITYNUM_WORLD; - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - fogMask = -((tr.refdef.rdflags & RDF_NOFOG) == 0); - - for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) { - sh = R_GetShaderByHandle( poly->hShader ); - R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex & fogMask, qfalse, qfalse, 0 /*cubeMap*/ ); - } -} - -/* -===================== -RE_AddPolyToScene - -===================== -*/ -void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) { - srfPoly_t *poly; - int i, j; - int fogIndex; - fog_t *fog; - vec3_t bounds[2]; - - if ( !tr.registered ) { - return; - } - - if ( !hShader ) { - // This isn't a useful warning, and an hShader of zero isn't a null shader, it's - // the default shader. - //ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n"); - //return; - } - - for ( j = 0; j < numPolys; j++ ) { - if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) { - /* - NOTE TTimo this was initially a PRINT_WARNING - but it happens a lot with high fighting scenes and particles - since we don't plan on changing the const and making for room for those effects - simply cut this message to developer only - */ - ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n"); - return; - } - - poly = &backEndData->polys[r_numpolys]; - poly->surfaceType = SF_POLY; - poly->hShader = hShader; - poly->numVerts = numVerts; - poly->verts = &backEndData->polyVerts[r_numpolyverts]; - - Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) ); - - if ( glConfig.hardwareType == GLHW_RAGEPRO ) { - poly->verts->modulate[0] = 255; - poly->verts->modulate[1] = 255; - poly->verts->modulate[2] = 255; - poly->verts->modulate[3] = 255; - } - // done. - r_numpolys++; - r_numpolyverts += numVerts; - - // if no world is loaded - if ( tr.world == NULL ) { - fogIndex = 0; - } - // see if it is in a fog volume - else if ( tr.world->numfogs == 1 ) { - fogIndex = 0; - } else { - // find which fog volume the poly is in - VectorCopy( poly->verts[0].xyz, bounds[0] ); - VectorCopy( poly->verts[0].xyz, bounds[1] ); - for ( i = 1 ; i < poly->numVerts ; i++ ) { - AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] ); - } - for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) { - fog = &tr.world->fogs[fogIndex]; - if ( bounds[1][0] >= fog->bounds[0][0] - && bounds[1][1] >= fog->bounds[0][1] - && bounds[1][2] >= fog->bounds[0][2] - && bounds[0][0] <= fog->bounds[1][0] - && bounds[0][1] <= fog->bounds[1][1] - && bounds[0][2] <= fog->bounds[1][2] ) { - break; - } - } - if ( fogIndex == tr.world->numfogs ) { - fogIndex = 0; - } - } - poly->fogIndex = fogIndex; - } -} - - -//================================================================================= - - -/* -===================== -RE_AddRefEntityToScene - -===================== -*/ -void RE_AddRefEntityToScene( const refEntity_t *ent ) { - vec3_t cross; - - if ( !tr.registered ) { - return; - } - if ( r_numentities >= MAX_REFENTITIES ) { - ri.Printf(PRINT_DEVELOPER, "RE_AddRefEntityToScene: Dropping refEntity, reached MAX_REFENTITIES\n"); - return; - } - if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) { - static qboolean firstTime = qtrue; - if (firstTime) { - firstTime = qfalse; - ri.Printf( PRINT_WARNING, "RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n"); - } - return; - } - if ( (int)ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) { - ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType ); - } - - backEndData->entities[r_numentities].e = *ent; - backEndData->entities[r_numentities].lightingCalculated = qfalse; - - CrossProduct(ent->axis[0], ent->axis[1], cross); - backEndData->entities[r_numentities].mirrored = (DotProduct(ent->axis[2], cross) < 0.f); - - r_numentities++; -} - - -/* -===================== -RE_AddDynamicLightToScene - -===================== -*/ -void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) { - dlight_t *dl; - - if ( !tr.registered ) { - return; - } - if ( r_numdlights >= MAX_DLIGHTS ) { - return; - } - if ( intensity <= 0 ) { - return; - } - // these cards don't have the correct blend mode - if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - return; - } - dl = &backEndData->dlights[r_numdlights++]; - VectorCopy (org, dl->origin); - dl->radius = intensity; - dl->color[0] = r; - dl->color[1] = g; - dl->color[2] = b; - dl->additive = additive; -} - -/* -===================== -RE_AddLightToScene - -===================== -*/ -void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { - RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse ); -} - -/* -===================== -RE_AddAdditiveLightToScene - -===================== -*/ -void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { - RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue ); -} - - -void RE_BeginScene(const refdef_t *fd) -{ - Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) ); - - tr.refdef.x = fd->x; - tr.refdef.y = fd->y; - tr.refdef.width = fd->width; - tr.refdef.height = fd->height; - tr.refdef.fov_x = fd->fov_x; - tr.refdef.fov_y = fd->fov_y; - - VectorCopy( fd->vieworg, tr.refdef.vieworg ); - VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] ); - VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] ); - VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] ); - - tr.refdef.time = fd->time; - tr.refdef.rdflags = fd->rdflags; - - // copy the areamask data over and note if it has changed, which - // will force a reset of the visible leafs even if the view hasn't moved - tr.refdef.areamaskModified = qfalse; - if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) { - int areaDiff; - int i; - - // compare the area bits - areaDiff = 0; - for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) { - areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i]; - ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i]; - } - - if ( areaDiff ) { - // a door just opened or something - tr.refdef.areamaskModified = qtrue; - } - } - - tr.refdef.sunDir[3] = 0.0f; - tr.refdef.sunCol[3] = 1.0f; - tr.refdef.sunAmbCol[3] = 1.0f; - - VectorCopy(tr.sunDirection, tr.refdef.sunDir); - if ( (tr.refdef.rdflags & RDF_NOWORLDMODEL) || !(r_depthPrepass->value) ){ - tr.refdef.colorScale = 1.0f; - VectorSet(tr.refdef.sunCol, 0, 0, 0); - VectorSet(tr.refdef.sunAmbCol, 0, 0, 0); - } - else - { - tr.refdef.colorScale = r_forceSun->integer ? r_forceSunMapLightScale->value : tr.mapLightScale; - - if (r_sunlightMode->integer == 1) - { - tr.refdef.sunCol[0] = - tr.refdef.sunCol[1] = - tr.refdef.sunCol[2] = 1.0f; - - tr.refdef.sunAmbCol[0] = - tr.refdef.sunAmbCol[1] = - tr.refdef.sunAmbCol[2] = r_forceSun->integer ? r_forceSunAmbientScale->value : tr.sunShadowScale; - } - else - { - float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8); - if (r_forceSun->integer) - { - VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol); - VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol); - } - else - { - VectorScale(tr.sunLight, scale, tr.refdef.sunCol); - VectorScale(tr.sunLight, scale * tr.sunShadowScale, tr.refdef.sunAmbCol); - } - } - } - - if (r_forceAutoExposure->integer) - { - tr.refdef.autoExposureMinMax[0] = r_forceAutoExposureMin->value; - tr.refdef.autoExposureMinMax[1] = r_forceAutoExposureMax->value; - } - else - { - tr.refdef.autoExposureMinMax[0] = tr.autoExposureMinMax[0]; - tr.refdef.autoExposureMinMax[1] = tr.autoExposureMinMax[1]; - } - - if (r_forceToneMap->integer) - { - tr.refdef.toneMinAvgMaxLinear[0] = pow(2, r_forceToneMapMin->value); - tr.refdef.toneMinAvgMaxLinear[1] = pow(2, r_forceToneMapAvg->value); - tr.refdef.toneMinAvgMaxLinear[2] = pow(2, r_forceToneMapMax->value); - } - else - { - tr.refdef.toneMinAvgMaxLinear[0] = pow(2, tr.toneMinAvgMaxLevel[0]); - tr.refdef.toneMinAvgMaxLinear[1] = pow(2, tr.toneMinAvgMaxLevel[1]); - tr.refdef.toneMinAvgMaxLinear[2] = pow(2, tr.toneMinAvgMaxLevel[2]); - } - - // Makro - copy exta info if present - if (fd->rdflags & RDF_EXTRA) { - const refdefex_t* extra = (const refdefex_t*) (fd+1); - - tr.refdef.blurFactor = extra->blurFactor; - - if (fd->rdflags & RDF_SUNLIGHT) - { - VectorCopy(extra->sunDir, tr.refdef.sunDir); - VectorCopy(extra->sunCol, tr.refdef.sunCol); - VectorCopy(extra->sunAmbCol, tr.refdef.sunAmbCol); - } - } - else - { - tr.refdef.blurFactor = 0.0f; - } - - // derived info - - tr.refdef.floatTime = tr.refdef.time * 0.001f; - - tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; - tr.refdef.drawSurfs = backEndData->drawSurfs; - - tr.refdef.num_entities = r_numentities - r_firstSceneEntity; - tr.refdef.entities = &backEndData->entities[r_firstSceneEntity]; - - tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; - tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight]; - - tr.refdef.numPolys = r_numpolys - r_firstScenePoly; - tr.refdef.polys = &backEndData->polys[r_firstScenePoly]; - - tr.refdef.num_pshadows = 0; - tr.refdef.pshadows = &backEndData->pshadows[0]; - - // turn off dynamic lighting globally by clearing all the - // dlights if it needs to be disabled or if vertex lighting is enabled - if ( r_dynamiclight->integer == 0 || - r_vertexLight->integer == 1 || - glConfig.hardwareType == GLHW_PERMEDIA2 ) { - tr.refdef.num_dlights = 0; - } - - // a single frame may have multiple scenes draw inside it -- - // a 3D game view, 3D status bar renderings, 3D menus, etc. - // They need to be distinguished by the light flare code, because - // the visibility state for a given surface may be different in - // each scene / view. - tr.frameSceneNum++; - tr.sceneCount++; -} - - -void RE_EndScene() -{ - // the next scene rendered in this frame will tack on after this one - r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; - r_firstSceneEntity = r_numentities; - r_firstSceneDlight = r_numdlights; - r_firstScenePoly = r_numpolys; -} - -/* -@@@@@@@@@@@@@@@@@@@@@ -RE_RenderScene - -Draw a 3D view into a part of the window, then return -to 2D drawing. - -Rendering a scene may require multiple views to be rendered -to handle mirrors, -@@@@@@@@@@@@@@@@@@@@@ -*/ -void RE_RenderScene( const refdef_t *fd ) { - viewParms_t parms; - int startTime; - - if ( !tr.registered ) { - return; - } - GLimp_LogComment( "====== RE_RenderScene =====\n" ); - - if ( r_norefresh->integer ) { - return; - } - - startTime = ri.Milliseconds(); - - if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { - ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); - } - - RE_BeginScene(fd); - - // SmileTheory: playing with shadow mapping - if (!( fd->rdflags & RDF_NOWORLDMODEL ) && tr.refdef.num_dlights && r_dlightMode->integer >= 2) - { - R_RenderDlightCubemaps(fd); - } - - /* playing with more shadows */ - if(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ) && r_shadows->integer == 4) - { - R_RenderPshadowMaps(fd); - } - - // playing with even more shadows - if(glRefConfig.framebufferObject && r_sunlightMode->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows)) - { - R_RenderSunShadowMaps(fd, 0); - R_RenderSunShadowMaps(fd, 1); - R_RenderSunShadowMaps(fd, 2); - } - - // playing with cube maps - // this is where dynamic cubemaps would be rendered - if (0) //(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL )) - { - int i, j; - - for (i = 0; i < tr.numCubemaps; i++) - { - for (j = 0; j < 6; j++) - { - R_RenderCubemapSide(i, j, qtrue); - } - } - } - - // setup view parms for the initial view - // - // set up viewport - // The refdef takes 0-at-the-top y coordinates, so - // convert to GL's 0-at-the-bottom space - // - Com_Memset( &parms, 0, sizeof( parms ) ); - parms.viewportX = tr.refdef.x; - parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); - parms.viewportWidth = tr.refdef.width; - parms.viewportHeight = tr.refdef.height; - parms.isPortal = qfalse; - - parms.fovX = tr.refdef.fov_x; - parms.fovY = tr.refdef.fov_y; - - parms.stereoFrame = tr.refdef.stereoFrame; - - VectorCopy( fd->vieworg, parms.or.origin ); - VectorCopy( fd->viewaxis[0], parms.or.axis[0] ); - VectorCopy( fd->viewaxis[1], parms.or.axis[1] ); - VectorCopy( fd->viewaxis[2], parms.or.axis[2] ); - - VectorCopy( fd->vieworg, parms.pvsOrigin ); - - if(!( fd->rdflags & RDF_NOWORLDMODEL ) && r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows)) - { - parms.flags = VPF_USESUNLIGHT; - } - - R_RenderView( &parms ); - - if(!( fd->rdflags & RDF_NOWORLDMODEL )) - R_AddPostProcessCmd(); - - RE_EndScene(); - - tr.frontEndMsec += ri.Milliseconds() - startTime; -} diff --git a/code/renderergl2/tr_shade.c b/code/renderergl2/tr_shade.c deleted file mode 100644 index 856b87483b..0000000000 --- a/code/renderergl2/tr_shade.c +++ /dev/null @@ -1,1652 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_shade.c - -#include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - -/* - - THIS ENTIRE FILE IS BACK END - - This file deals with applying shaders to surface data in the tess struct. -*/ - - -/* -================== -R_DrawElements - -================== -*/ - -void R_DrawElementsVBO( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ) -{ - if (glRefConfig.drawRangeElements) - qglDrawRangeElementsEXT(GL_TRIANGLES, minIndex, maxIndex, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t))); - else - qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t))); - -} - - -static void R_DrawMultiElementsVBO( int multiDrawPrimitives, glIndex_t *multiDrawMinIndex, glIndex_t *multiDrawMaxIndex, - GLsizei *multiDrawNumIndexes, glIndex_t **multiDrawFirstIndex) -{ - if (glRefConfig.multiDrawArrays) - { - qglMultiDrawElementsEXT(GL_TRIANGLES, multiDrawNumIndexes, GL_INDEX_TYPE, (const GLvoid **)multiDrawFirstIndex, multiDrawPrimitives); - } - else - { - int i; - - if (glRefConfig.drawRangeElements) - { - for (i = 0; i < multiDrawPrimitives; i++) - { - qglDrawRangeElementsEXT(GL_TRIANGLES, multiDrawMinIndex[i], multiDrawMaxIndex[i], multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]); - } - } - else - { - for (i = 0; i < multiDrawPrimitives; i++) - { - qglDrawElements(GL_TRIANGLES, multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]); - } - } - } -} - - -/* -============================================================= - -SURFACE SHADERS - -============================================================= -*/ - -shaderCommands_t tess; - - -/* -================= -R_BindAnimatedImageToTMU - -================= -*/ -static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) { - int index; - - if ( bundle->isVideoMap ) { - int oldtmu = glState.currenttmu; - GL_SelectTexture(tmu); - ri.CIN_RunCinematic(bundle->videoMapHandle); - ri.CIN_UploadCinematic(bundle->videoMapHandle); - GL_SelectTexture(oldtmu); - return; - } - - if ( bundle->numImageAnimations <= 1 ) { - GL_BindToTMU( bundle->image[0], tmu); - return; - } - - // it is necessary to do this messy calc to make sure animations line up - // exactly with waveforms of the same frequency - index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); - index >>= FUNCTABLE_SIZE2; - - if ( index < 0 ) { - index = 0; // may happen with shader time offsets - } - index %= bundle->numImageAnimations; - - GL_BindToTMU( bundle->image[ index ], tmu ); -} - - -/* -================ -DrawTris - -Draws triangle outlines for debugging -================ -*/ -static void DrawTris (shaderCommands_t *input) { - GL_Bind( tr.whiteImage ); - - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); - qglDepthRange( 0, 0 ); - - { - shaderProgram_t *sp = &tr.textureColorShader; - vec4_t color; - - GLSL_VertexAttribsState(ATTR_POSITION); - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - VectorSet4(color, 1, 1, 1, 1); - GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); - - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } - } - - qglDepthRange( 0, 1 ); -} - - -/* -================ -DrawNormals - -Draws vertex normals for debugging -================ -*/ -static void DrawNormals (shaderCommands_t *input) { - //FIXME: implement this -} - -/* -============== -RB_BeginSurface - -We must set some things up before beginning any tesselation, -because a surface may be forced to perform a RB_End due -to overflow. -============== -*/ -void RB_BeginSurface( shader_t *shader, int fogNum, int cubemapIndex ) { - - shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader; - - tess.numIndexes = 0; - tess.firstIndex = 0; - tess.numVertexes = 0; - tess.multiDrawPrimitives = 0; - tess.shader = state; - tess.fogNum = fogNum; - tess.cubemapIndex = cubemapIndex; - tess.dlightBits = 0; // will be OR'd in by surface functions - tess.pshadowBits = 0; // will be OR'd in by surface functions - tess.xstages = state->stages; - tess.numPasses = state->numUnfoggedPasses; - tess.currentStageIteratorFunc = state->optimalStageIteratorFunc; - tess.useInternalVBO = qtrue; - - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) { - tess.shaderTime = tess.shader->clampTime; - } - - if (backEnd.viewParms.flags & VPF_SHADOWMAP) - { - tess.currentStageIteratorFunc = RB_StageIteratorGeneric; - } -} - - - -extern float EvalWaveForm( const waveForm_t *wf ); -extern float EvalWaveFormClamped( const waveForm_t *wf ); - - -static void ComputeTexMods( shaderStage_t *pStage, int bundleNum, float *outMatrix, float *outOffTurb) -{ - int tm; - float matrix[6], currentmatrix[6]; - textureBundle_t *bundle = &pStage->bundle[bundleNum]; - - matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = 0.0f; - matrix[1] = 0.0f; matrix[3] = 1.0f; matrix[5] = 0.0f; - - currentmatrix[0] = 1.0f; currentmatrix[2] = 0.0f; currentmatrix[4] = 0.0f; - currentmatrix[1] = 0.0f; currentmatrix[3] = 1.0f; currentmatrix[5] = 0.0f; - - outMatrix[0] = 1.0f; outMatrix[2] = 0.0f; - outMatrix[1] = 0.0f; outMatrix[3] = 1.0f; - - outOffTurb[0] = 0.0f; outOffTurb[1] = 0.0f; outOffTurb[2] = 0.0f; outOffTurb[3] = 0.0f; - - for ( tm = 0; tm < bundle->numTexMods ; tm++ ) { - switch ( bundle->texMods[tm].type ) - { - - case TMOD_NONE: - tm = TR_MAX_TEXMODS; // break out of for loop - break; - - case TMOD_TURBULENT: - RB_CalcTurbulentFactors(&bundle->texMods[tm].wave, &outOffTurb[2], &outOffTurb[3]); - break; - - case TMOD_ENTITY_TRANSLATE: - RB_CalcScrollTexMatrix( backEnd.currentEntity->e.shaderTexCoord, matrix ); - break; - - case TMOD_SCROLL: - RB_CalcScrollTexMatrix( bundle->texMods[tm].scroll, - matrix ); - break; - - case TMOD_SCALE: - RB_CalcScaleTexMatrix( bundle->texMods[tm].scale, - matrix ); - break; - - case TMOD_STRETCH: - RB_CalcStretchTexMatrix( &bundle->texMods[tm].wave, - matrix ); - break; - - case TMOD_TRANSFORM: - RB_CalcTransformTexMatrix( &bundle->texMods[tm], - matrix ); - break; - - case TMOD_ROTATE: - RB_CalcRotateTexMatrix( bundle->texMods[tm].rotateSpeed, - matrix ); - break; - - default: - ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'", bundle->texMods[tm].type, tess.shader->name ); - break; - } - - switch ( bundle->texMods[tm].type ) - { - case TMOD_NONE: - case TMOD_TURBULENT: - default: - break; - - case TMOD_ENTITY_TRANSLATE: - case TMOD_SCROLL: - case TMOD_SCALE: - case TMOD_STRETCH: - case TMOD_TRANSFORM: - case TMOD_ROTATE: - outMatrix[0] = matrix[0] * currentmatrix[0] + matrix[2] * currentmatrix[1]; - outMatrix[1] = matrix[1] * currentmatrix[0] + matrix[3] * currentmatrix[1]; - - outMatrix[2] = matrix[0] * currentmatrix[2] + matrix[2] * currentmatrix[3]; - outMatrix[3] = matrix[1] * currentmatrix[2] + matrix[3] * currentmatrix[3]; - - outOffTurb[0] = matrix[0] * currentmatrix[4] + matrix[2] * currentmatrix[5] + matrix[4]; - outOffTurb[1] = matrix[1] * currentmatrix[4] + matrix[3] * currentmatrix[5] + matrix[5]; - - currentmatrix[0] = outMatrix[0]; - currentmatrix[1] = outMatrix[1]; - currentmatrix[2] = outMatrix[2]; - currentmatrix[3] = outMatrix[3]; - currentmatrix[4] = outOffTurb[0]; - currentmatrix[5] = outOffTurb[1]; - break; - } - } -} - - -static void ComputeDeformValues(int *deformGen, vec5_t deformParams) -{ - // u_DeformGen - *deformGen = DGEN_NONE; - if(!ShaderRequiresCPUDeforms(tess.shader)) - { - deformStage_t *ds; - - // only support the first one - ds = &tess.shader->deforms[0]; - - switch (ds->deformation) - { - case DEFORM_WAVE: - *deformGen = ds->deformationWave.func; - - deformParams[0] = ds->deformationWave.base; - deformParams[1] = ds->deformationWave.amplitude; - deformParams[2] = ds->deformationWave.phase; - deformParams[3] = ds->deformationWave.frequency; - deformParams[4] = ds->deformationSpread; - break; - - case DEFORM_BULGE: - *deformGen = DGEN_BULGE; - - deformParams[0] = 0; - deformParams[1] = ds->bulgeHeight; // amplitude - deformParams[2] = ds->bulgeWidth; // phase - deformParams[3] = ds->bulgeSpeed; // frequency - deformParams[4] = 0; - break; - - default: - break; - } - } -} - - -static void ProjectDlightTexture( void ) { - int l; - vec3_t origin; - float scale; - float radius; - int deformGen; - vec5_t deformParams; - - if ( !backEnd.refdef.num_dlights ) { - return; - } - - ComputeDeformValues(&deformGen, deformParams); - - for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { - dlight_t *dl; - shaderProgram_t *sp; - vec4_t vector; - - if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light - } - - dl = &backEnd.refdef.dlights[l]; - VectorCopy( dl->transformed, origin ); - radius = dl->radius; - scale = 1.0f / radius; - - sp = &tr.dlightShader[deformGen == DGEN_NONE ? 0 : 1]; - - backEnd.pc.c_dlightDraws++; - - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - - GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); - if (deformGen != DGEN_NONE) - { - GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); - } - - vector[0] = dl->color[0]; - vector[1] = dl->color[1]; - vector[2] = dl->color[2]; - vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_COLOR, vector); - - vector[0] = origin[0]; - vector[1] = origin[1]; - vector[2] = origin[2]; - vector[3] = scale; - GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector); - - GL_Bind( tr.dlightImage ); - - // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light - // where they aren't rendered - if ( dl->additive ) { - GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - else { - GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - - if (tess.multiDrawPrimitives) - { - shaderCommands_t *input = &tess; - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); - } - - backEnd.pc.c_totalIndexes += tess.numIndexes; - backEnd.pc.c_dlightIndexes += tess.numIndexes; - backEnd.pc.c_dlightVertexes += tess.numVertexes; - } -} - - -static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t vertColor, int blend ) -{ - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 1.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 0.0f; - - // - // rgbGen - // - switch ( pStage->rgbGen ) - { - case CGEN_IDENTITY_LIGHTING: - baseColor[0] = - baseColor[1] = - baseColor[2] = tr.identityLight; - break; - case CGEN_EXACT_VERTEX: - case CGEN_EXACT_VERTEX_LIT: - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 0.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 1.0f; - break; - case CGEN_CONST: - baseColor[0] = pStage->constantColor[0] / 255.0f; - baseColor[1] = pStage->constantColor[1] / 255.0f; - baseColor[2] = pStage->constantColor[2] / 255.0f; - baseColor[3] = pStage->constantColor[3] / 255.0f; - break; - case CGEN_VERTEX: - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 0.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = tr.identityLight; - vertColor[3] = 1.0f; - break; - case CGEN_VERTEX_LIT: - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 0.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = tr.identityLight; - break; - case CGEN_ONE_MINUS_VERTEX: - baseColor[0] = - baseColor[1] = - baseColor[2] = tr.identityLight; - - vertColor[0] = - vertColor[1] = - vertColor[2] = -tr.identityLight; - break; - case CGEN_FOG: - { - fog_t *fog; - - fog = tr.world->fogs + tess.fogNum; - - baseColor[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f; - baseColor[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f; - baseColor[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f; - baseColor[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f; - } - break; - case CGEN_WAVEFORM: - baseColor[0] = - baseColor[1] = - baseColor[2] = RB_CalcWaveColorSingle( &pStage->rgbWave ); - break; - case CGEN_ENTITY: - if (backEnd.currentEntity) - { - baseColor[0] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[0] / 255.0f; - baseColor[1] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[1] / 255.0f; - baseColor[2] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f; - baseColor[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; - } - break; - case CGEN_ONE_MINUS_ENTITY: - if (backEnd.currentEntity) - { - baseColor[0] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[0] / 255.0f; - baseColor[1] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[1] / 255.0f; - baseColor[2] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f; - baseColor[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; - } - break; - case CGEN_IDENTITY: - case CGEN_LIGHTING_DIFFUSE: - case CGEN_BAD: - break; - } - - // - // alphaGen - // - switch ( pStage->alphaGen ) - { - case AGEN_SKIP: - break; - case AGEN_CONST: - baseColor[3] = pStage->constantColor[3] / 255.0f; - vertColor[3] = 0.0f; - break; - case AGEN_WAVEFORM: - baseColor[3] = RB_CalcWaveAlphaSingle( &pStage->alphaWave ); - vertColor[3] = 0.0f; - break; - case AGEN_ENTITY: - if (backEnd.currentEntity) - { - baseColor[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; - } - vertColor[3] = 0.0f; - break; - case AGEN_ONE_MINUS_ENTITY: - if (backEnd.currentEntity) - { - baseColor[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; - } - vertColor[3] = 0.0f; - break; - case AGEN_VERTEX: - baseColor[3] = 0.0f; - vertColor[3] = 1.0f; - break; - case AGEN_ONE_MINUS_VERTEX: - baseColor[3] = 1.0f; - vertColor[3] = -1.0f; - break; - case AGEN_IDENTITY: - case AGEN_LIGHTING_SPECULAR: - case AGEN_PORTAL: - // Done entirely in vertex program - baseColor[3] = 1.0f; - vertColor[3] = 0.0f; - break; - } - - // multiply color by overbrightbits if this isn't a blend - if (r_softOverbright->integer && tr.overbrightBits - && !((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_DST_COLOR) - && !((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR) - && !((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_SRC_COLOR) - && !((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR)) - { - float scale = 1 << tr.overbrightBits; - - baseColor[0] *= scale; - baseColor[1] *= scale; - baseColor[2] *= scale; - vertColor[0] *= scale; - vertColor[1] *= scale; - vertColor[2] *= scale; - } - - // FIXME: find some way to implement this. -#if 0 - // if in greyscale rendering mode turn all color values into greyscale. - if(r_greyscale->integer) - { - int scale; - - for(i = 0; i < tess.numVertexes; i++) - { - scale = (tess.svars.colors[i][0] + tess.svars.colors[i][1] + tess.svars.colors[i][2]) / 3; - tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; - } - } -#endif -} - - -static void ComputeFogValues(vec4_t fogDistanceVector, vec4_t fogDepthVector, float *eyeT) -{ - // from RB_CalcFogTexCoords() - fog_t *fog; - vec3_t local; - - if (!tess.fogNum) - return; - - fog = tr.world->fogs + tess.fogNum; - - VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); - fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; - fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; - fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; - fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); - - // scale the fog vectors based on the fog's thickness - VectorScale4(fogDistanceVector, fog->tcScale, fogDistanceVector); - - // rotate the gradient vector for this orientation - if ( fog->hasSurface ) { - fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + - fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; - fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + - fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; - fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + - fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; - fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); - - *eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; - } else { - *eyeT = 1; // non-surface fog always has eye inside - } -} - - -static void ComputeFogColorMask( shaderStage_t *pStage, vec4_t fogColorMask ) -{ - switch(pStage->adjustColorsForFog) - { - case ACFF_MODULATE_RGB: - fogColorMask[0] = - fogColorMask[1] = - fogColorMask[2] = 1.0f; - fogColorMask[3] = 0.0f; - break; - case ACFF_MODULATE_ALPHA: - fogColorMask[0] = - fogColorMask[1] = - fogColorMask[2] = 0.0f; - fogColorMask[3] = 1.0f; - break; - case ACFF_MODULATE_RGBA: - fogColorMask[0] = - fogColorMask[1] = - fogColorMask[2] = - fogColorMask[3] = 1.0f; - break; - default: - fogColorMask[0] = - fogColorMask[1] = - fogColorMask[2] = - fogColorMask[3] = 0.0f; - break; - } -} - - -static void ForwardDlight( void ) { - int l; - //vec3_t origin; - //float scale; - float radius; - - int deformGen; - vec5_t deformParams; - - vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - float eyeT = 0; - - shaderCommands_t *input = &tess; - shaderStage_t *pStage = tess.xstages[0]; - - if ( !backEnd.refdef.num_dlights ) { - return; - } - - ComputeDeformValues(&deformGen, deformParams); - - ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); - - for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { - dlight_t *dl; - shaderProgram_t *sp; - vec4_t vector; - vec4_t texMatrix; - vec4_t texOffTurb; - - if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light - } - - dl = &backEnd.refdef.dlights[l]; - //VectorCopy( dl->transformed, origin ); - radius = dl->radius; - //scale = 1.0f / radius; - - //if (pStage->glslShaderGroup == tr.lightallShader) - { - int index = pStage->glslShaderIndex; - - index &= ~LIGHTDEF_LIGHTTYPE_MASK; - index |= LIGHTDEF_USE_LIGHT_VECTOR; - - sp = &tr.lightallShader[index]; - } - - backEnd.pc.c_lightallDraws++; - - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); - GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin); - - GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - - GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); - if (deformGen != DGEN_NONE) - { - GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); - } - - if ( input->fogNum ) { - vec4_t fogColorMask; - - GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); - GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); - GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); - - ComputeFogColorMask(pStage, fogColorMask); - - GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); - } - - { - vec4_t baseColor; - vec4_t vertColor; - - ComputeShaderColors(pStage, baseColor, vertColor, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); - - GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); - GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); - } - - if (pStage->alphaGen == AGEN_PORTAL) - { - GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange); - } - - GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen); - GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen); - - GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, dl->color); - - VectorSet(vector, 0, 0, 0); - GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vector); - - VectorCopy(dl->origin, vector); - vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); - - GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius); - - GLSL_SetUniformVec2(sp, UNIFORM_MATERIALINFO, pStage->materialInfo); - - // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light - // where they aren't rendered - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); - - if (pStage->bundle[TB_DIFFUSEMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); - - if (pStage->bundle[TB_NORMALMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); - - if (pStage->bundle[TB_SPECULARMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); - - if (r_dlightMode->integer >= 2) - { - GL_SelectTexture(TB_SHADOWMAP); - GL_Bind(tr.shadowCubemaps[l]); - GL_SelectTexture(0); - } - - ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb); - - GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); - - // - // draw - // - - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } - - backEnd.pc.c_totalIndexes += tess.numIndexes; - backEnd.pc.c_dlightIndexes += tess.numIndexes; - backEnd.pc.c_dlightVertexes += tess.numVertexes; - } -} - - -static void ProjectPshadowVBOGLSL( void ) { - int l; - vec3_t origin; - float radius; - - int deformGen; - vec5_t deformParams; - - shaderCommands_t *input = &tess; - - if ( !backEnd.refdef.num_pshadows ) { - return; - } - - ComputeDeformValues(&deformGen, deformParams); - - for ( l = 0 ; l < backEnd.refdef.num_pshadows ; l++ ) { - pshadow_t *ps; - shaderProgram_t *sp; - vec4_t vector; - - if ( !( tess.pshadowBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this shadow - } - - ps = &backEnd.refdef.pshadows[l]; - VectorCopy( ps->lightOrigin, origin ); - radius = ps->lightRadius; - - sp = &tr.pshadowShader; - - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - VectorCopy(origin, vector); - vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); - - VectorScale(ps->lightViewAxis[0], 1.0f / ps->viewRadius, vector); - GLSL_SetUniformVec3(sp, UNIFORM_LIGHTFORWARD, vector); - - VectorScale(ps->lightViewAxis[1], 1.0f / ps->viewRadius, vector); - GLSL_SetUniformVec3(sp, UNIFORM_LIGHTRIGHT, vector); - - VectorScale(ps->lightViewAxis[2], 1.0f / ps->viewRadius, vector); - GLSL_SetUniformVec3(sp, UNIFORM_LIGHTUP, vector); - - GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius); - - // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light - // where they aren't rendered - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); - - GL_BindToTMU( tr.pshadowMaps[l], TB_DIFFUSEMAP ); - - // - // draw - // - - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } - - backEnd.pc.c_totalIndexes += tess.numIndexes; - //backEnd.pc.c_dlightIndexes += tess.numIndexes; - } -} - - - -/* -=================== -RB_FogPass - -Blends a fog texture on top of everything else -=================== -*/ -static void RB_FogPass( void ) { - fog_t *fog; - vec4_t color; - vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - float eyeT = 0; - shaderProgram_t *sp; - - int deformGen; - vec5_t deformParams; - - ComputeDeformValues(&deformGen, deformParams); - - { - int index = 0; - - if (deformGen != DGEN_NONE) - index |= FOGDEF_USE_DEFORM_VERTEXES; - - if (glState.vertexAnimation) - index |= FOGDEF_USE_VERTEX_ANIMATION; - - sp = &tr.fogShader[index]; - } - - backEnd.pc.c_fogDraws++; - - GLSL_BindProgram(sp); - - fog = tr.world->fogs + tess.fogNum; - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - - GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); - if (deformGen != DGEN_NONE) - { - GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); - } - - color[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f; - color[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f; - color[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f; - color[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f; - GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); - - ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); - - GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); - GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); - GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); - - if ( tess.shader->fogPass == FP_EQUAL ) { - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); - } else { - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - } - - if (tess.multiDrawPrimitives) - { - shaderCommands_t *input = &tess; - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); - } -} - - -static unsigned int RB_CalcShaderVertexAttribs( shaderCommands_t *input ) -{ - unsigned int vertexAttribs = input->shader->vertexAttribs; - - if(glState.vertexAnimation) - { - vertexAttribs |= ATTR_POSITION2; - if (vertexAttribs & ATTR_NORMAL) - { - vertexAttribs |= ATTR_NORMAL2; -#ifdef USE_VERT_TANGENT_SPACE - vertexAttribs |= ATTR_TANGENT2; -#endif - } - } - - return vertexAttribs; -} - -static void RB_IterateStagesGeneric( shaderCommands_t *input ) -{ - int stage; - - vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - float eyeT = 0; - - int deformGen; - vec5_t deformParams; - - ComputeDeformValues(&deformGen, deformParams); - - ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); - - for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) - { - shaderStage_t *pStage = input->xstages[stage]; - shaderProgram_t *sp; - vec4_t texMatrix; - vec4_t texOffTurb; - - if ( !pStage ) - { - break; - } - - if (backEnd.depthFill) - { - if (pStage->glslShaderGroup == tr.lightallShader) - { - int index = 0; - - if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity) - { - index |= LIGHTDEF_ENTITY; - } - - if (pStage->stateBits & GLS_ATEST_BITS) - { - index |= LIGHTDEF_USE_TCGEN_AND_TCMOD; - } - - sp = &pStage->glslShaderGroup[index]; - } - else - { - int shaderAttribs = 0; - - if (tess.shader->numDeforms && !ShaderRequiresCPUDeforms(tess.shader)) - { - shaderAttribs |= GENERICDEF_USE_DEFORM_VERTEXES; - } - - if (glState.vertexAnimation) - { - shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION; - } - - if (pStage->stateBits & GLS_ATEST_BITS) - { - shaderAttribs |= GENERICDEF_USE_TCGEN_AND_TCMOD; - } - - sp = &tr.genericShader[shaderAttribs]; - } - } - else if (pStage->glslShaderGroup == tr.lightallShader) - { - int index = pStage->glslShaderIndex; - - if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity) - { - index |= LIGHTDEF_ENTITY; - } - - if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (index & LIGHTDEF_LIGHTTYPE_MASK)) - { - index |= LIGHTDEF_USE_SHADOWMAP; - } - - if (r_lightmap->integer && index & LIGHTDEF_USE_LIGHTMAP) - { - index = LIGHTDEF_USE_LIGHTMAP; - } - - sp = &pStage->glslShaderGroup[index]; - - backEnd.pc.c_lightallDraws++; - } - else - { - sp = GLSL_GetGenericShaderProgram(stage); - - backEnd.pc.c_genericDraws++; - } - - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); - GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin); - - GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - - GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); - if (deformGen != DGEN_NONE) - { - GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); - } - - if ( input->fogNum ) { - GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); - GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); - GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); - } - - GL_State( pStage->stateBits ); - - { - vec4_t baseColor; - vec4_t vertColor; - - ComputeShaderColors(pStage, baseColor, vertColor, pStage->stateBits); - - if ((backEnd.refdef.colorScale != 1.0f) && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) - { - // use VectorScale to only scale first three values, not alpha - VectorScale(baseColor, backEnd.refdef.colorScale, baseColor); - VectorScale(vertColor, backEnd.refdef.colorScale, vertColor); - } - - GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); - GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); - } - - if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE) - { - vec4_t vec; - - VectorScale(backEnd.currentEntity->ambientLight, 1.0f / 255.0f, vec); - GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vec); - - VectorScale(backEnd.currentEntity->directedLight, 1.0f / 255.0f, vec); - GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, vec); - - VectorCopy(backEnd.currentEntity->lightDir, vec); - vec[3] = 0.0f; - GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vec); - GLSL_SetUniformVec3(sp, UNIFORM_MODELLIGHTDIR, backEnd.currentEntity->modelLightDir); - - GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, 0.0f); - } - - if (pStage->alphaGen == AGEN_PORTAL) - { - GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange); - } - - GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen); - GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen); - - if ( input->fogNum ) - { - vec4_t fogColorMask; - - ComputeFogColorMask(pStage, fogColorMask); - - GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); - } - - ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb); - - GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); - if (pStage->bundle[0].tcGen == TCGEN_VECTOR) - { - vec3_t vec; - - VectorCopy(pStage->bundle[0].tcGenVectors[0], vec); - GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR0, vec); - VectorCopy(pStage->bundle[0].tcGenVectors[1], vec); - GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR1, vec); - } - - GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); - - GLSL_SetUniformVec2(sp, UNIFORM_MATERIALINFO, pStage->materialInfo); - - //GLSL_SetUniformFloat(sp, UNIFORM_MAPLIGHTSCALE, backEnd.refdef.mapLightScale); - - // - // do multitexture - // - if ( backEnd.depthFill ) - { - if (!(pStage->stateBits & GLS_ATEST_BITS)) - GL_BindToTMU( tr.whiteImage, 0 ); - else if ( pStage->bundle[TB_COLORMAP].image[0] != 0 ) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_COLORMAP], TB_COLORMAP ); - } - else if ( pStage->glslShaderGroup == tr.lightallShader ) - { - int i; - vec4_t enableTextures; - - if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK)) - { - GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP); - GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTAMBIENT, backEnd.refdef.sunAmbCol); - GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTCOLOR, backEnd.refdef.sunCol); - GLSL_SetUniformVec4(sp, UNIFORM_PRIMARYLIGHTORIGIN, backEnd.refdef.sunDir); - } - - VectorSet4(enableTextures, 0, 0, 0, 0); - if ((r_lightmap->integer == 1 || r_lightmap->integer == 2) && pStage->bundle[TB_LIGHTMAP].image[0]) - { - for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) - { - if (i == TB_LIGHTMAP) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_LIGHTMAP], i); - else - GL_BindToTMU( tr.whiteImage, i ); - } - } - else if (r_lightmap->integer == 3 && pStage->bundle[TB_DELUXEMAP].image[0]) - { - for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) - { - if (i == TB_LIGHTMAP) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], i); - else - GL_BindToTMU( tr.whiteImage, i ); - } - } - else - { - qboolean light = (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) != 0; - qboolean fastLight = !(r_normalMapping->integer || r_specularMapping->integer); - - if (pStage->bundle[TB_DIFFUSEMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); - - if (pStage->bundle[TB_LIGHTMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_LIGHTMAP], TB_LIGHTMAP); - - // bind textures that are sampled and used in the glsl shader, and - // bind whiteImage to textures that are sampled but zeroed in the glsl shader - // - // alternatives: - // - use the last bound texture - // -> costs more to sample a higher res texture then throw out the result - // - disable texture sampling in glsl shader with #ifdefs, as before - // -> increases the number of shaders that must be compiled - // - if (light && !fastLight) - { - if (pStage->bundle[TB_NORMALMAP].image[0]) - { - R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); - enableTextures[0] = 1.0f; - } - else if (r_normalMapping->integer) - GL_BindToTMU( tr.whiteImage, TB_NORMALMAP ); - - if (pStage->bundle[TB_DELUXEMAP].image[0]) - { - R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], TB_DELUXEMAP); - enableTextures[1] = 1.0f; - } - else if (r_deluxeMapping->integer) - GL_BindToTMU( tr.whiteImage, TB_DELUXEMAP ); - - if (pStage->bundle[TB_SPECULARMAP].image[0]) - { - R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); - enableTextures[2] = 1.0f; - } - else if (r_specularMapping->integer) - GL_BindToTMU( tr.whiteImage, TB_SPECULARMAP ); - } - - enableTextures[3] = (r_cubeMapping->integer && !(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex) ? 1.0f : 0.0f; - } - - GLSL_SetUniformVec4(sp, UNIFORM_ENABLETEXTURES, enableTextures); - } - else if ( pStage->bundle[1].image[0] != 0 ) - { - R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 ); - - // - // lightmap/secondary pass - // - if ( r_lightmap->integer ) { - GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, GL_REPLACE); - } else { - GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, tess.shader->multitextureEnv); - } - - R_BindAnimatedImageToTMU( &pStage->bundle[1], 1 ); - } - else - { - // - // set state - // - R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 ); - - GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, 0); - } - - // - // testing cube map - // - if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex && r_cubeMapping->integer) - GL_BindToTMU( tr.cubemaps[input->cubemapIndex - 1], TB_CUBEMAP); - - // - // draw - // - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } - - // allow skipping out to show just lightmaps during development - if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) - { - break; - } - - if (backEnd.depthFill) - break; - } -} - - -static void RB_RenderShadowmap( shaderCommands_t *input ) -{ - int deformGen; - vec5_t deformParams; - - ComputeDeformValues(&deformGen, deformParams); - - { - shaderProgram_t *sp = &tr.shadowmapShader; - - vec4_t vector; - - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); - - GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - - GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); - if (deformGen != DGEN_NONE) - { - GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); - } - - VectorCopy(backEnd.viewParms.or.origin, vector); - vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); - GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, backEnd.viewParms.zFar); - - GL_State( 0 ); - - // - // do multitexture - // - //if ( pStage->glslShaderGroup ) - { - // - // draw - // - - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } - } - } -} - - - -/* -** RB_StageIteratorGeneric -*/ -void RB_StageIteratorGeneric( void ) -{ - shaderCommands_t *input; - unsigned int vertexAttribs = 0; - - input = &tess; - - if (!input->numVertexes || !input->numIndexes) - { - return; - } - - if (tess.useInternalVBO) - { - RB_DeformTessGeometry(); - } - - vertexAttribs = RB_CalcShaderVertexAttribs( input ); - - if (tess.useInternalVBO) - { - RB_UpdateVBOs(vertexAttribs); - } - else - { - backEnd.pc.c_staticVboDraws++; - } - - // - // log this call - // - if ( r_logFile->integer ) - { - // don't just call LogComment, or we will get - // a call to va() every frame! - GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) ); - } - - // - // set face culling appropriately - // - if ((backEnd.viewParms.flags & VPF_DEPTHSHADOW)) - { - //GL_Cull( CT_TWO_SIDED ); - - if (input->shader->cullType == CT_TWO_SIDED) - GL_Cull( CT_TWO_SIDED ); - else if (input->shader->cullType == CT_FRONT_SIDED) - GL_Cull( CT_BACK_SIDED ); - else - GL_Cull( CT_FRONT_SIDED ); - - } - else - GL_Cull( input->shader->cullType ); - - // set polygon offset if necessary - if ( input->shader->polygonOffset ) - { - qglEnable( GL_POLYGON_OFFSET_FILL ); - qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); - } - - // - // Set vertex attribs and pointers - // - GLSL_VertexAttribsState(vertexAttribs); - - // - // render depth if in depthfill mode - // - if (backEnd.depthFill) - { - RB_IterateStagesGeneric( input ); - - // - // reset polygon offset - // - if ( input->shader->polygonOffset ) - { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } - - return; - } - - // - // render shadowmap if in shadowmap mode - // - if (backEnd.viewParms.flags & VPF_SHADOWMAP) - { - if ( input->shader->sort == SS_OPAQUE ) - { - RB_RenderShadowmap( input ); - } - // - // reset polygon offset - // - if ( input->shader->polygonOffset ) - { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } - - return; - } - - // - // - // call shader function - // - RB_IterateStagesGeneric( input ); - - // - // pshadows! - // - if (glRefConfig.framebufferObject && r_shadows->integer == 4 && tess.pshadowBits - && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { - ProjectPshadowVBOGLSL(); - } - - - // - // now do any dynamic lighting needed - // - if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE - && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { - if (tess.shader->numUnfoggedPasses == 1 && tess.xstages[0]->glslShaderGroup == tr.lightallShader - && (tess.xstages[0]->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && r_dlightMode->integer) - { - ForwardDlight(); - } - else - { - ProjectDlightTexture(); - } - } - - // - // now do fog - // - if ( tess.fogNum && tess.shader->fogPass ) { - RB_FogPass(); - } - - // - // reset polygon offset - // - if ( input->shader->polygonOffset ) - { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } -} - - -/* -** RB_EndSurface -*/ -void RB_EndSurface( void ) { - shaderCommands_t *input; - - input = &tess; - - if (input->numIndexes == 0 || input->numVertexes == 0) { - return; - } - - if (input->indexes[SHADER_MAX_INDEXES-1] != 0) { - ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit"); - } - if (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) { - ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit"); - } - - if ( tess.shader == tr.shadowShader ) { - RB_ShadowTessEnd(); - return; - } - - // for debugging of sort order issues, stop rendering after a given sort value - if ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) { - return; - } - - // - // update performance counters - // - backEnd.pc.c_shaders++; - backEnd.pc.c_vertexes += tess.numVertexes; - backEnd.pc.c_indexes += tess.numIndexes; - backEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses; - - // - // call off to shader specific tess end function - // - tess.currentStageIteratorFunc(); - - // - // draw debugging stuff - // - if ( r_showtris->integer ) { - DrawTris (input); - } - if ( r_shownormals->integer ) { - DrawNormals (input); - } - // clear shader so we can tell we don't have any unclosed surfaces - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - tess.multiDrawPrimitives = 0; - - GLimp_LogComment( "----------\n" ); -} diff --git a/code/renderergl2/tr_shade_calc.c b/code/renderergl2/tr_shade_calc.c deleted file mode 100644 index c9816fa8b6..0000000000 --- a/code/renderergl2/tr_shade_calc.c +++ /dev/null @@ -1,819 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_shade_calc.c - -#include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - - -#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ri.ftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) - -static float *TableForFunc( genFunc_t func ) -{ - switch ( func ) - { - case GF_SIN: - return tr.sinTable; - case GF_TRIANGLE: - return tr.triangleTable; - case GF_SQUARE: - return tr.squareTable; - case GF_SAWTOOTH: - return tr.sawToothTable; - case GF_INVERSE_SAWTOOTH: - return tr.inverseSawToothTable; - case GF_NONE: - default: - break; - } - - ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'", func, tess.shader->name ); - return NULL; -} - -/* -** EvalWaveForm -** -** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly -*/ -static float EvalWaveForm( const waveForm_t *wf ) -{ - float *table; - - table = TableForFunc( wf->func ); - - return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency ); -} - -static float EvalWaveFormClamped( const waveForm_t *wf ) -{ - float glow = EvalWaveForm( wf ); - - if ( glow < 0 ) - { - return 0; - } - - if ( glow > 1 ) - { - return 1; - } - - return glow; -} - -/* -** RB_CalcStretchTexMatrix -*/ -void RB_CalcStretchTexMatrix( const waveForm_t *wf, float *matrix ) -{ - float p; - - p = 1.0f / EvalWaveForm( wf ); - - matrix[0] = p; matrix[2] = 0; matrix[4] = 0.5f - 0.5f * p; - matrix[1] = 0; matrix[3] = p; matrix[5] = 0.5f - 0.5f * p; -} - -/* -==================================================================== - -DEFORMATIONS - -==================================================================== -*/ - -/* -======================== -RB_CalcDeformVertexes - -======================== -*/ -void RB_CalcDeformVertexes( deformStage_t *ds ) -{ - int i; - vec3_t offset; - float scale; - float *xyz = ( float * ) tess.xyz; - uint32_t *normal = tess.normal; - float *table; - - if ( ds->deformationWave.frequency == 0 ) - { - scale = EvalWaveForm( &ds->deformationWave ); - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) - { - R_VboUnpackNormal(offset, *normal); - - xyz[0] += offset[0] * scale; - xyz[1] += offset[1] * scale; - xyz[2] += offset[2] * scale; - } - } - else - { - table = TableForFunc( ds->deformationWave.func ); - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) - { - float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread; - - scale = WAVEVALUE( table, ds->deformationWave.base, - ds->deformationWave.amplitude, - ds->deformationWave.phase + off, - ds->deformationWave.frequency ); - - R_VboUnpackNormal(offset, *normal); - - xyz[0] += offset[0] * scale; - xyz[1] += offset[1] * scale; - xyz[2] += offset[2] * scale; - } - } -} - -/* -========================= -RB_CalcDeformNormals - -Wiggle the normals for wavy environment mapping -========================= -*/ -void RB_CalcDeformNormals( deformStage_t *ds ) { - int i; - float scale; - float *xyz = ( float * ) tess.xyz; - uint32_t *normal = tess.normal; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) { - vec3_t fNormal; - - R_VboUnpackNormal(fNormal, *normal); - - scale = 0.98f; - scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - fNormal[ 0 ] += ds->deformationWave.amplitude * scale; - - scale = 0.98f; - scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - fNormal[ 1 ] += ds->deformationWave.amplitude * scale; - - scale = 0.98f; - scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - fNormal[ 2 ] += ds->deformationWave.amplitude * scale; - - VectorNormalizeFast( fNormal ); - - *normal = R_VboPackNormal(fNormal); - } -} - -/* -======================== -RB_CalcBulgeVertexes - -======================== -*/ -void RB_CalcBulgeVertexes( deformStage_t *ds ) { - int i; - const float *st = ( const float * ) tess.texCoords[0]; - float *xyz = ( float * ) tess.xyz; - uint32_t *normal = tess.normal; - float now; - - now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal++ ) { - int off; - float scale; - vec3_t fNormal; - - R_VboUnpackNormal(fNormal, *normal); - - off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now ); - - scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight; - - xyz[0] += fNormal[0] * scale; - xyz[1] += fNormal[1] * scale; - xyz[2] += fNormal[2] * scale; - } -} - - -/* -====================== -RB_CalcMoveVertexes - -A deformation that can move an entire surface along a wave path -====================== -*/ -void RB_CalcMoveVertexes( deformStage_t *ds ) { - int i; - float *xyz; - float *table; - float scale; - vec3_t offset; - - table = TableForFunc( ds->deformationWave.func ); - - scale = WAVEVALUE( table, ds->deformationWave.base, - ds->deformationWave.amplitude, - ds->deformationWave.phase, - ds->deformationWave.frequency ); - - VectorScale( ds->moveVector, scale, offset ); - - xyz = ( float * ) tess.xyz; - for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) { - VectorAdd( xyz, offset, xyz ); - } -} - - -/* -============= -DeformText - -Change a polygon into a bunch of text polygons -============= -*/ -void DeformText( const char *text ) { - int i; - vec3_t origin, width, height; - int len; - int ch; - float color[4]; - float bottom, top; - vec3_t mid; - vec3_t fNormal; - - height[0] = 0; - height[1] = 0; - height[2] = -1; - - R_VboUnpackNormal(fNormal, tess.normal[0]); - CrossProduct( fNormal, height, width ); - - // find the midpoint of the box - VectorClear( mid ); - bottom = 999999; - top = -999999; - for ( i = 0 ; i < 4 ; i++ ) { - VectorAdd( tess.xyz[i], mid, mid ); - if ( tess.xyz[i][2] < bottom ) { - bottom = tess.xyz[i][2]; - } - if ( tess.xyz[i][2] > top ) { - top = tess.xyz[i][2]; - } - } - VectorScale( mid, 0.25f, origin ); - - // determine the individual character size - height[0] = 0; - height[1] = 0; - height[2] = ( top - bottom ) * 0.5f; - - VectorScale( width, height[2] * -0.75f, width ); - - // determine the starting position - len = strlen( text ); - VectorMA( origin, (len-1), width, origin ); - - // clear the shader indexes - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - - color[0] = color[1] = color[2] = color[3] = 1.0f; - - // draw each character - for ( i = 0 ; i < len ; i++ ) { - ch = text[i]; - ch &= 255; - - if ( ch != ' ' ) { - int row, col; - float frow, fcol, size; - - row = ch>>4; - col = ch&15; - - frow = row*0.0625f; - fcol = col*0.0625f; - size = 0.0625f; - - RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size ); - } - VectorMA( origin, -2, width, origin ); - } -} - -/* -================== -GlobalVectorToLocal -================== -*/ -static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) { - out[0] = DotProduct( in, backEnd.or.axis[0] ); - out[1] = DotProduct( in, backEnd.or.axis[1] ); - out[2] = DotProduct( in, backEnd.or.axis[2] ); -} - -/* -===================== -AutospriteDeform - -Assuming all the triangles for this shader are independant -quads, rebuild them as forward facing sprites -===================== -*/ -static void AutospriteDeform( void ) { - int i; - int oldVerts; - float *xyz; - vec3_t mid, delta; - float radius; - vec3_t left, up; - vec3_t leftDir, upDir; - - if ( tess.numVertexes & 3 ) { - ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count\n", tess.shader->name ); - } - if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) { - ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count\n", tess.shader->name ); - } - - oldVerts = tess.numVertexes; - tess.numVertexes = 0; - tess.numIndexes = 0; - tess.firstIndex = 0; - - if ( backEnd.currentEntity != &tr.worldEntity ) { - GlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir ); - GlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir ); - } else { - VectorCopy( backEnd.viewParms.or.axis[1], leftDir ); - VectorCopy( backEnd.viewParms.or.axis[2], upDir ); - } - - for ( i = 0 ; i < oldVerts ; i+=4 ) { - // find the midpoint - xyz = tess.xyz[i]; - - mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]); - mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]); - mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]); - - VectorSubtract( xyz, mid, delta ); - radius = VectorLength( delta ) * 0.707f; // / sqrt(2) - - VectorScale( leftDir, radius, left ); - VectorScale( upDir, radius, up ); - - if ( backEnd.viewParms.isMirror ) { - VectorSubtract( vec3_origin, left, left ); - } - - // compensate for scale in the axes if necessary - if ( backEnd.currentEntity->e.nonNormalizedAxes ) { - float axisLength; - axisLength = VectorLength( backEnd.currentEntity->e.axis[0] ); - if ( !axisLength ) { - axisLength = 0; - } else { - axisLength = 1.0f / axisLength; - } - VectorScale(left, axisLength, left); - VectorScale(up, axisLength, up); - } - - RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] ); - } -} - - -/* -===================== -Autosprite2Deform - -Autosprite2 will pivot a rectangular quad along the center of its long axis -===================== -*/ -int edgeVerts[6][2] = { - { 0, 1 }, - { 0, 2 }, - { 0, 3 }, - { 1, 2 }, - { 1, 3 }, - { 2, 3 } -}; - -static void Autosprite2Deform( void ) { - int i, j, k; - int indexes; - float *xyz; - vec3_t forward; - - if ( tess.numVertexes & 3 ) { - ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count\n", tess.shader->name ); - } - if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) { - ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count\n", tess.shader->name ); - } - - if ( backEnd.currentEntity != &tr.worldEntity ) { - GlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward ); - } else { - VectorCopy( backEnd.viewParms.or.axis[0], forward ); - } - - // this is a lot of work for two triangles... - // we could precalculate a lot of it is an issue, but it would mess up - // the shader abstraction - for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) { - float lengths[2]; - int nums[2]; - vec3_t mid[2]; - vec3_t major, minor; - float *v1, *v2; - - // find the midpoint - xyz = tess.xyz[i]; - - // identify the two shortest edges - nums[0] = nums[1] = 0; - lengths[0] = lengths[1] = 999999; - - for ( j = 0 ; j < 6 ; j++ ) { - float l; - vec3_t temp; - - v1 = xyz + 4 * edgeVerts[j][0]; - v2 = xyz + 4 * edgeVerts[j][1]; - - VectorSubtract( v1, v2, temp ); - - l = DotProduct( temp, temp ); - if ( l < lengths[0] ) { - nums[1] = nums[0]; - lengths[1] = lengths[0]; - nums[0] = j; - lengths[0] = l; - } else if ( l < lengths[1] ) { - nums[1] = j; - lengths[1] = l; - } - } - - for ( j = 0 ; j < 2 ; j++ ) { - v1 = xyz + 4 * edgeVerts[nums[j]][0]; - v2 = xyz + 4 * edgeVerts[nums[j]][1]; - - mid[j][0] = 0.5f * (v1[0] + v2[0]); - mid[j][1] = 0.5f * (v1[1] + v2[1]); - mid[j][2] = 0.5f * (v1[2] + v2[2]); - } - - // find the vector of the major axis - VectorSubtract( mid[1], mid[0], major ); - - // cross this with the view direction to get minor axis - CrossProduct( major, forward, minor ); - VectorNormalize( minor ); - - // re-project the points - for ( j = 0 ; j < 2 ; j++ ) { - float l; - - v1 = xyz + 4 * edgeVerts[nums[j]][0]; - v2 = xyz + 4 * edgeVerts[nums[j]][1]; - - l = 0.5 * sqrt( lengths[j] ); - - // we need to see which direction this edge - // is used to determine direction of projection - for ( k = 0 ; k < 5 ; k++ ) { - if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0] - && tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) { - break; - } - } - - if ( k == 5 ) { - VectorMA( mid[j], l, minor, v1 ); - VectorMA( mid[j], -l, minor, v2 ); - } else { - VectorMA( mid[j], -l, minor, v1 ); - VectorMA( mid[j], l, minor, v2 ); - } - } - } -} - - -/* -===================== -RB_DeformTessGeometry - -===================== -*/ -void RB_DeformTessGeometry( void ) { - int i; - deformStage_t *ds; - - if(!ShaderRequiresCPUDeforms(tess.shader)) - { - // we don't need the following CPU deforms - return; - } - - for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) { - ds = &tess.shader->deforms[ i ]; - - switch ( ds->deformation ) { - case DEFORM_NONE: - break; - case DEFORM_NORMALS: - RB_CalcDeformNormals( ds ); - break; - case DEFORM_WAVE: - RB_CalcDeformVertexes( ds ); - break; - case DEFORM_BULGE: - RB_CalcBulgeVertexes( ds ); - break; - case DEFORM_MOVE: - RB_CalcMoveVertexes( ds ); - break; - case DEFORM_PROJECTION_SHADOW: - RB_ProjectionShadowDeform(); - break; - case DEFORM_AUTOSPRITE: - AutospriteDeform(); - break; - case DEFORM_AUTOSPRITE2: - Autosprite2Deform(); - break; - case DEFORM_TEXT0: - case DEFORM_TEXT1: - case DEFORM_TEXT2: - case DEFORM_TEXT3: - case DEFORM_TEXT4: - case DEFORM_TEXT5: - case DEFORM_TEXT6: - case DEFORM_TEXT7: - DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] ); - break; - } - } -} - -/* -==================================================================== - -COLORS - -==================================================================== -*/ - - -/* -** RB_CalcWaveColorSingle -*/ -float RB_CalcWaveColorSingle( const waveForm_t *wf ) -{ - float glow; - - if ( wf->func == GF_NOISE ) { - glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude; - } else { - glow = EvalWaveForm( wf ) * tr.identityLight; - } - - if ( glow < 0 ) { - glow = 0; - } - else if ( glow > 1 ) { - glow = 1; - } - - return glow; -} - -/* -** RB_CalcWaveAlphaSingle -*/ -float RB_CalcWaveAlphaSingle( const waveForm_t *wf ) -{ - return EvalWaveFormClamped( wf ); -} - -/* -** RB_CalcModulateColorsByFog -*/ -void RB_CalcModulateColorsByFog( unsigned char *colors ) { - int i; - float texCoords[SHADER_MAX_VERTEXES][2]; - - // calculate texcoords so we can derive density - // this is not wasted, because it would only have - // been previously called if the surface was opaque - RB_CalcFogTexCoords( texCoords[0] ); - - for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { - float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); - colors[0] *= f; - colors[1] *= f; - colors[2] *= f; - } -} - - -/* -==================================================================== - -TEX COORDS - -==================================================================== -*/ - -/* -======================== -RB_CalcFogTexCoords - -To do the clipped fog plane really correctly, we should use -projected textures, but I don't trust the drivers and it -doesn't fit our shader data. -======================== -*/ -void RB_CalcFogTexCoords( float *st ) { - int i; - float *v; - float s, t; - float eyeT; - qboolean eyeOutside; - fog_t *fog; - vec3_t local; - vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - - fog = tr.world->fogs + tess.fogNum; - - // all fogging distance is based on world Z units - VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); - fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; - fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; - fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; - fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); - - // scale the fog vectors based on the fog's thickness - fogDistanceVector[0] *= fog->tcScale; - fogDistanceVector[1] *= fog->tcScale; - fogDistanceVector[2] *= fog->tcScale; - fogDistanceVector[3] *= fog->tcScale; - - // rotate the gradient vector for this orientation - if ( fog->hasSurface ) { - fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + - fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; - fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + - fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; - fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + - fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; - fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); - - eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; - } else { - eyeT = 1; // non-surface fog always has eye inside - } - - // see if the viewpoint is outside - // this is needed for clipping distance even for constant fog - - if ( eyeT < 0 ) { - eyeOutside = qtrue; - } else { - eyeOutside = qfalse; - } - - fogDistanceVector[3] += 1.0/512; - - // calculate density for each point - for (i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4) { - // calculate the length in fog - s = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3]; - t = DotProduct( v, fogDepthVector ) + fogDepthVector[3]; - - // partially clipped fogs use the T axis - if ( eyeOutside ) { - if ( t < 1.0 ) { - t = 1.0/32; // point is outside, so no fogging - } else { - t = 1.0/32 + 30.0/32 * t / ( t - eyeT ); // cut the distance at the fog plane - } - } else { - if ( t < 0 ) { - t = 1.0/32; // point is outside, so no fogging - } else { - t = 31.0/32; - } - } - - st[0] = s; - st[1] = t; - st += 2; - } -} - -/* -** RB_CalcTurbulentFactors -*/ -void RB_CalcTurbulentFactors( const waveForm_t *wf, float *amplitude, float *now ) -{ - *now = wf->phase + tess.shaderTime * wf->frequency; - *amplitude = wf->amplitude; -} - -/* -** RB_CalcScaleTexMatrix -*/ -void RB_CalcScaleTexMatrix( const float scale[2], float *matrix ) -{ - matrix[0] = scale[0]; matrix[2] = 0.0f; matrix[4] = 0.0f; - matrix[1] = 0.0f; matrix[3] = scale[1]; matrix[5] = 0.0f; -} - -/* -** RB_CalcScrollTexMatrix -*/ -void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix ) -{ - float timeScale = tess.shaderTime; - float adjustedScrollS, adjustedScrollT; - - adjustedScrollS = scrollSpeed[0] * timeScale; - adjustedScrollT = scrollSpeed[1] * timeScale; - - // clamp so coordinates don't continuously get larger, causing problems - // with hardware limits - adjustedScrollS = adjustedScrollS - floor( adjustedScrollS ); - adjustedScrollT = adjustedScrollT - floor( adjustedScrollT ); - - matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = adjustedScrollS; - matrix[1] = 0.0f; matrix[3] = 1.0f; matrix[5] = adjustedScrollT; -} - -/* -** RB_CalcTransformTexMatrix -*/ -void RB_CalcTransformTexMatrix( const texModInfo_t *tmi, float *matrix ) -{ - matrix[0] = tmi->matrix[0][0]; matrix[2] = tmi->matrix[1][0]; matrix[4] = tmi->translate[0]; - matrix[1] = tmi->matrix[0][1]; matrix[3] = tmi->matrix[1][1]; matrix[5] = tmi->translate[1]; -} - -/* -** RB_CalcRotateTexMatrix -*/ -void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix ) -{ - float timeScale = tess.shaderTime; - float degs; - int index; - float sinValue, cosValue; - - degs = -degsPerSecond * timeScale; - index = degs * ( FUNCTABLE_SIZE / 360.0f ); - - sinValue = tr.sinTable[ index & FUNCTABLE_MASK ]; - cosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ]; - - matrix[0] = cosValue; matrix[2] = -sinValue; matrix[4] = 0.5 - 0.5 * cosValue + 0.5 * sinValue; - matrix[1] = sinValue; matrix[3] = cosValue; matrix[5] = 0.5 - 0.5 * sinValue - 0.5 * cosValue; -} diff --git a/code/renderergl2/tr_shader.c b/code/renderergl2/tr_shader.c deleted file mode 100644 index 6dbac55a36..0000000000 --- a/code/renderergl2/tr_shader.c +++ /dev/null @@ -1,3863 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -// tr_shader.c -- this file deals with the parsing and definition of shaders - -static char *s_shaderText; - -// the shader is parsed into these global variables, then copied into -// dynamically allocated memory if it is valid. -static shaderStage_t stages[MAX_SHADER_STAGES]; -static shader_t shader; -static texModInfo_t texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS]; - -#define FILE_HASH_SIZE 1024 -static shader_t* hashTable[FILE_HASH_SIZE]; - -#define MAX_SHADERTEXT_HASH 2048 -static char **shaderTextHashTable[MAX_SHADERTEXT_HASH]; - -/* -================ -return a hash value for the filename -================ -*/ -#ifdef __GNUCC__ - #warning TODO: check if long is ok here -#endif -static long generateHashValue( const char *fname, const int size ) { - int i; - long hash; - char letter; - - hash = 0; - i = 0; - while (fname[i] != '\0') { - letter = tolower(fname[i]); - if (letter =='.') break; // don't include extension - if (letter =='\\') letter = '/'; // damn path names - if (letter == PATH_SEP) letter = '/'; // damn path names - hash+=(long)(letter)*(i+119); - i++; - } - hash = (hash ^ (hash >> 10) ^ (hash >> 20)); - hash &= (size-1); - return hash; -} - -void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) { - char strippedName[MAX_QPATH]; - int hash; - shader_t *sh, *sh2; - qhandle_t h; - - sh = R_FindShaderByName( shaderName ); - if (sh == NULL || sh == tr.defaultShader) { - h = RE_RegisterShaderLightMap(shaderName, 0); - sh = R_GetShaderByHandle(h); - } - if (sh == NULL || sh == tr.defaultShader) { - ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName ); - return; - } - - sh2 = R_FindShaderByName( newShaderName ); - if (sh2 == NULL || sh2 == tr.defaultShader) { - h = RE_RegisterShaderLightMap(newShaderName, 0); - sh2 = R_GetShaderByHandle(h); - } - - if (sh2 == NULL || sh2 == tr.defaultShader) { - ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName ); - return; - } - - // remap all the shaders with the given name - // even tho they might have different lightmaps - COM_StripExtension(shaderName, strippedName, sizeof(strippedName)); - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - for (sh = hashTable[hash]; sh; sh = sh->next) { - if (Q_stricmp(sh->name, strippedName) == 0) { - if (sh != sh2) { - sh->remappedShader = sh2; - } else { - sh->remappedShader = NULL; - } - } - } - if (timeOffset) { - sh2->timeOffset = atof(timeOffset); - } -} - -/* -=============== -ParseVector -=============== -*/ -static qboolean ParseVector( char **text, int count, float *v ) { - char *token; - int i; - - // FIXME: spaces are currently required after parens, should change parseext... - token = COM_ParseExt( text, qfalse ); - if ( strcmp( token, "(" ) ) { - ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name ); - return qfalse; - } - - for ( i = 0 ; i < count ; i++ ) { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) { - ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name ); - return qfalse; - } - v[i] = atof( token ); - } - - token = COM_ParseExt( text, qfalse ); - if ( strcmp( token, ")" ) ) { - ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name ); - return qfalse; - } - - return qtrue; -} - - -/* -=============== -NameToAFunc -=============== -*/ -static unsigned NameToAFunc( const char *funcname ) -{ - if ( !Q_stricmp( funcname, "GT0" ) ) - { - return GLS_ATEST_GT_0; - } - else if ( !Q_stricmp( funcname, "LT128" ) ) - { - return GLS_ATEST_LT_80; - } - else if ( !Q_stricmp( funcname, "GE128" ) ) - { - return GLS_ATEST_GE_80; - } - - ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name ); - return 0; -} - - -/* -=============== -NameToSrcBlendMode -=============== -*/ -static int NameToSrcBlendMode( const char *name ) -{ - if ( !Q_stricmp( name, "GL_ONE" ) ) - { - return GLS_SRCBLEND_ONE; - } - else if ( !Q_stricmp( name, "GL_ZERO" ) ) - { - return GLS_SRCBLEND_ZERO; - } - else if ( !Q_stricmp( name, "GL_DST_COLOR" ) ) - { - return GLS_SRCBLEND_DST_COLOR; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) ) - { - return GLS_SRCBLEND_ONE_MINUS_DST_COLOR; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) - { - return GLS_SRCBLEND_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) - { - return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) - { - if (r_ignoreDstAlpha->integer) - return GLS_SRCBLEND_ONE; - - return GLS_SRCBLEND_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) - { - if (r_ignoreDstAlpha->integer) - return GLS_SRCBLEND_ZERO; - - return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) ) - { - return GLS_SRCBLEND_ALPHA_SATURATE; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name ); - return GLS_SRCBLEND_ONE; -} - -/* -=============== -NameToDstBlendMode -=============== -*/ -static int NameToDstBlendMode( const char *name ) -{ - if ( !Q_stricmp( name, "GL_ONE" ) ) - { - return GLS_DSTBLEND_ONE; - } - else if ( !Q_stricmp( name, "GL_ZERO" ) ) - { - return GLS_DSTBLEND_ZERO; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) - { - return GLS_DSTBLEND_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) - { - return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) - { - if (r_ignoreDstAlpha->integer) - return GLS_DSTBLEND_ONE; - - return GLS_DSTBLEND_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) - { - if (r_ignoreDstAlpha->integer) - return GLS_DSTBLEND_ZERO; - - return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) ) - { - return GLS_DSTBLEND_SRC_COLOR; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) ) - { - return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name ); - return GLS_DSTBLEND_ONE; -} - -/* -=============== -NameToGenFunc -=============== -*/ -static genFunc_t NameToGenFunc( const char *funcname ) -{ - if ( !Q_stricmp( funcname, "sin" ) ) - { - return GF_SIN; - } - else if ( !Q_stricmp( funcname, "square" ) ) - { - return GF_SQUARE; - } - else if ( !Q_stricmp( funcname, "triangle" ) ) - { - return GF_TRIANGLE; - } - else if ( !Q_stricmp( funcname, "sawtooth" ) ) - { - return GF_SAWTOOTH; - } - else if ( !Q_stricmp( funcname, "inversesawtooth" ) ) - { - return GF_INVERSE_SAWTOOTH; - } - else if ( !Q_stricmp( funcname, "noise" ) ) - { - return GF_NOISE; - } - - ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name ); - return GF_SIN; -} - - -/* -=================== -ParseWaveForm -=================== -*/ -static void ParseWaveForm( char **text, waveForm_t *wave ) -{ - char *token; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->func = NameToGenFunc( token ); - - // BASE, AMP, PHASE, FREQ - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->base = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->phase = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->frequency = atof( token ); -} - - -/* -=================== -ParseTexMod -=================== -*/ -static void ParseTexMod( char *_text, shaderStage_t *stage ) -{ - const char *token; - char **text = &_text; - texModInfo_t *tmi; - - if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) { - ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'", shader.name ); - return; - } - - tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods]; - stage->bundle[0].numTexMods++; - - token = COM_ParseExt( text, qfalse ); - - // - // turb - // - if ( !Q_stricmp( token, "turb" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.base = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.amplitude = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.phase = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.frequency = atof( token ); - - tmi->type = TMOD_TURBULENT; - } - // - // scale - // - else if ( !Q_stricmp( token, "scale" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name ); - return; - } - tmi->scale[0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name ); - return; - } - tmi->scale[1] = atof( token ); - tmi->type = TMOD_SCALE; - } - // - // scroll - // - else if ( !Q_stricmp( token, "scroll" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); - return; - } - tmi->scroll[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); - return; - } - tmi->scroll[1] = atof( token ); - tmi->type = TMOD_SCROLL; - } - // - // stretch - // - else if ( !Q_stricmp( token, "stretch" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.func = NameToGenFunc( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.base = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.phase = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.frequency = atof( token ); - - tmi->type = TMOD_STRETCH; - } - // - // transform - // - else if ( !Q_stricmp( token, "transform" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[0][0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[0][1] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[1][0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[1][1] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->translate[0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->translate[1] = atof( token ); - - tmi->type = TMOD_TRANSFORM; - } - // - // rotate - // - else if ( !Q_stricmp( token, "rotate" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name ); - return; - } - tmi->rotateSpeed = atof( token ); - tmi->type = TMOD_ROTATE; - } - // - // entityTranslate - // - else if ( !Q_stricmp( token, "entityTranslate" ) ) - { - tmi->type = TMOD_ENTITY_TRANSLATE; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name ); - } -} - - -/* -=================== -ParseStage -=================== -*/ -static qboolean ParseStage( shaderStage_t *stage, char **text ) -{ - char *token; - int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0; - qboolean depthMaskExplicit = qfalse; - - stage->active = qtrue; - - while ( 1 ) - { - token = COM_ParseExt( text, qtrue ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" ); - return qfalse; - } - - if ( token[0] == '}' ) - { - break; - } - // - // map - // - else if ( !Q_stricmp( token, "map" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if ( !Q_stricmp( token, "$whiteimage" ) ) - { - stage->bundle[0].image[0] = tr.whiteImage; - continue; - } - else if ( !Q_stricmp( token, "$lightmap" ) ) - { - stage->bundle[0].isLightmap = qtrue; - if ( shader.lightmapIndex < 0 ) { - stage->bundle[0].image[0] = tr.whiteImage; - } else { - stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - } - continue; - } - else if ( !Q_stricmp( token, "$deluxemap" ) ) - { - if (!tr.worldDeluxeMapping) - { - ri.Printf( PRINT_WARNING, "WARNING: shader '%s' wants a deluxe map in a map compiled without them\n", shader.name ); - return qfalse; - } - - stage->bundle[0].isLightmap = qtrue; - if ( shader.lightmapIndex < 0 ) { - stage->bundle[0].image[0] = tr.whiteImage; - } else { - stage->bundle[0].image[0] = tr.deluxemaps[shader.lightmapIndex]; - } - continue; - } - else - { - imgType_t type = IMGTYPE_COLORALPHA; - imgFlags_t flags = IMGFLAG_NONE; - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - if (stage->type == ST_NORMALMAP || stage->type == ST_NORMALPARALLAXMAP) - { - type = IMGTYPE_NORMAL; - flags |= IMGFLAG_NOLIGHTSCALE; - - if (stage->type == ST_NORMALPARALLAXMAP) - type = IMGTYPE_NORMALHEIGHT; - } - else - { - if (r_genNormalMaps->integer) - flags |= IMGFLAG_GENNORMALMAP; - - if (r_srgb->integer) - flags |= IMGFLAG_SRGB; - } - - stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); - - if ( !stage->bundle[0].image[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - } - // - // clampmap - // - else if ( !Q_stricmp( token, "clampmap" ) ) - { - imgType_t type = IMGTYPE_COLORALPHA; - imgFlags_t flags = IMGFLAG_CLAMPTOEDGE; - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - if (stage->type == ST_NORMALMAP || stage->type == ST_NORMALPARALLAXMAP) - { - type = IMGTYPE_NORMAL; - flags |= IMGFLAG_NOLIGHTSCALE; - - if (stage->type == ST_NORMALPARALLAXMAP) - type = IMGTYPE_NORMALHEIGHT; - } - else - { - if (r_genNormalMaps->integer) - flags |= IMGFLAG_GENNORMALMAP; - - if (r_srgb->integer) - flags |= IMGFLAG_SRGB; - } - - - stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); - if ( !stage->bundle[0].image[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - // - // animMap .... - // - else if ( !Q_stricmp( token, "animMap" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[0].imageAnimationSpeed = atof( token ); - - // parse up to MAX_IMAGE_ANIMATIONS animations - while ( 1 ) { - int num; - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) { - break; - } - num = stage->bundle[0].numImageAnimations; - if ( num < MAX_IMAGE_ANIMATIONS ) { - imgFlags_t flags = IMGFLAG_NONE; - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - if (r_srgb->integer) - flags |= IMGFLAG_SRGB; - - stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); - if ( !stage->bundle[0].image[num] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - stage->bundle[0].numImageAnimations++; - } - } - } - else if ( !Q_stricmp( token, "videoMap" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); - if (stage->bundle[0].videoMapHandle != -1) { - stage->bundle[0].isVideoMap = qtrue; - stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle]; - } - } - // - // alphafunc - // - else if ( !Q_stricmp( token, "alphaFunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - atestBits = NameToAFunc( token ); - } - // - // depthFunc - // - else if ( !Q_stricmp( token, "depthfunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if ( !Q_stricmp( token, "lequal" ) ) - { - depthFuncBits = 0; - } - else if ( !Q_stricmp( token, "equal" ) ) - { - depthFuncBits = GLS_DEPTHFUNC_EQUAL; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // detail - // - else if ( !Q_stricmp( token, "detail" ) ) - { - stage->isDetail = qtrue; - } - // - // blendfunc - // or blendfunc - // - else if ( !Q_stricmp( token, "blendfunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); - continue; - } - // check for "simple" blends first - if ( !Q_stricmp( token, "add" ) ) { - blendSrcBits = GLS_SRCBLEND_ONE; - blendDstBits = GLS_DSTBLEND_ONE; - } else if ( !Q_stricmp( token, "filter" ) ) { - blendSrcBits = GLS_SRCBLEND_DST_COLOR; - blendDstBits = GLS_DSTBLEND_ZERO; - } else if ( !Q_stricmp( token, "blend" ) ) { - blendSrcBits = GLS_SRCBLEND_SRC_ALPHA; - blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else { - // complex double blends - blendSrcBits = NameToSrcBlendMode( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); - continue; - } - blendDstBits = NameToDstBlendMode( token ); - } - - // clear depth mask for blended surfaces - if ( !depthMaskExplicit ) - { - depthMaskBits = 0; - } - } - // - // stage - // - else if(!Q_stricmp(token, "stage")) - { - token = COM_ParseExt(text, qfalse); - if(token[0] == 0) - { - ri.Printf(PRINT_WARNING, "WARNING: missing parameters for stage in shader '%s'\n", shader.name); - continue; - } - - if(!Q_stricmp(token, "diffuseMap")) - { - stage->type = ST_DIFFUSEMAP; - } - else if(!Q_stricmp(token, "normalMap") || !Q_stricmp(token, "bumpMap")) - { - stage->type = ST_NORMALMAP; - } - else if(!Q_stricmp(token, "normalParallaxMap") || !Q_stricmp(token, "bumpParallaxMap")) - { - if (r_parallaxMapping->integer) - stage->type = ST_NORMALPARALLAXMAP; - else - stage->type = ST_NORMALMAP; - } - else if(!Q_stricmp(token, "specularMap")) - { - stage->type = ST_SPECULARMAP; - stage->materialInfo[0] = 1.0f; - stage->materialInfo[1] = 1.0f; - } - else - { - ri.Printf(PRINT_WARNING, "WARNING: unknown stage parameter '%s' in shader '%s'\n", token, shader.name); - continue; - } - } - // - // specularReflectance - // - else if (!Q_stricmp(token, "specularreflectance")) - { - token = COM_ParseExt(text, qfalse); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular reflectance in shader '%s'\n", shader.name ); - continue; - } - stage->materialInfo[0] = atof( token ); - } - // - // specularExponent - // - else if (!Q_stricmp(token, "specularexponent")) - { - float exponent; - - token = COM_ParseExt(text, qfalse); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular exponent in shader '%s'\n", shader.name ); - continue; - } - - exponent = atof( token ); - - // Change shininess to gloss - // FIXME: assumes max exponent of 8192 and min of 1, must change here if altered in lightall_fp.glsl - exponent = CLAMP(exponent, 1.0, 8192.0); - - stage->materialInfo[1] = log(exponent) / log(8192.0); - } - // - // gloss - // - else if (!Q_stricmp(token, "gloss")) - { - token = COM_ParseExt(text, qfalse); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for gloss in shader '%s'\n", shader.name ); - continue; - } - - stage->materialInfo[1] = atof( token ); - } - // - // rgbGen - // - else if ( !Q_stricmp( token, "rgbGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - ParseWaveForm( text, &stage->rgbWave ); - stage->rgbGen = CGEN_WAVEFORM; - } - else if ( !Q_stricmp( token, "const" ) ) - { - vec3_t color; - - ParseVector( text, 3, color ); - stage->constantColor[0] = 255 * color[0]; - stage->constantColor[1] = 255 * color[1]; - stage->constantColor[2] = 255 * color[2]; - - stage->rgbGen = CGEN_CONST; - } - else if ( !Q_stricmp( token, "identity" ) ) - { - stage->rgbGen = CGEN_IDENTITY; - } - else if ( !Q_stricmp( token, "identityLighting" ) ) - { - stage->rgbGen = CGEN_IDENTITY_LIGHTING; - } - else if ( !Q_stricmp( token, "entity" ) ) - { - stage->rgbGen = CGEN_ENTITY; - } - else if ( !Q_stricmp( token, "oneMinusEntity" ) ) - { - stage->rgbGen = CGEN_ONE_MINUS_ENTITY; - } - else if ( !Q_stricmp( token, "vertex" ) ) - { - stage->rgbGen = CGEN_VERTEX; - if ( stage->alphaGen == 0 ) { - stage->alphaGen = AGEN_VERTEX; - } - } - else if ( !Q_stricmp( token, "exactVertex" ) ) - { - stage->rgbGen = CGEN_EXACT_VERTEX; - } - else if ( !Q_stricmp( token, "vertexLit" ) ) - { - stage->rgbGen = CGEN_VERTEX_LIT; - if ( stage->alphaGen == 0 ) { - stage->alphaGen = AGEN_VERTEX; - } - } - else if ( !Q_stricmp( token, "exactVertexLit" ) ) - { - stage->rgbGen = CGEN_EXACT_VERTEX_LIT; - } - else if ( !Q_stricmp( token, "lightingDiffuse" ) ) - { - stage->rgbGen = CGEN_LIGHTING_DIFFUSE; - } - else if ( !Q_stricmp( token, "oneMinusVertex" ) ) - { - stage->rgbGen = CGEN_ONE_MINUS_VERTEX; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // alphaGen - // - else if ( !Q_stricmp( token, "alphaGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - ParseWaveForm( text, &stage->alphaWave ); - stage->alphaGen = AGEN_WAVEFORM; - } - else if ( !Q_stricmp( token, "const" ) ) - { - token = COM_ParseExt( text, qfalse ); - stage->constantColor[3] = 255 * atof( token ); - stage->alphaGen = AGEN_CONST; - } - else if ( !Q_stricmp( token, "identity" ) ) - { - stage->alphaGen = AGEN_IDENTITY; - } - else if ( !Q_stricmp( token, "entity" ) ) - { - stage->alphaGen = AGEN_ENTITY; - } - else if ( !Q_stricmp( token, "oneMinusEntity" ) ) - { - stage->alphaGen = AGEN_ONE_MINUS_ENTITY; - } - else if ( !Q_stricmp( token, "vertex" ) ) - { - stage->alphaGen = AGEN_VERTEX; - } - else if ( !Q_stricmp( token, "lightingSpecular" ) ) - { - stage->alphaGen = AGEN_LIGHTING_SPECULAR; - } - else if ( !Q_stricmp( token, "oneMinusVertex" ) ) - { - stage->alphaGen = AGEN_ONE_MINUS_VERTEX; - } - else if ( !Q_stricmp( token, "portal" ) ) - { - stage->alphaGen = AGEN_PORTAL; - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - shader.portalRange = 256; - ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name ); - } - else - { - shader.portalRange = atof( token ); - } - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // tcGen - // - else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "environment" ) ) - { - stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED; - } - else if ( !Q_stricmp( token, "lightmap" ) ) - { - stage->bundle[0].tcGen = TCGEN_LIGHTMAP; - } - else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) ) - { - stage->bundle[0].tcGen = TCGEN_TEXTURE; - } - else if ( !Q_stricmp( token, "vector" ) ) - { - ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] ); - ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] ); - - stage->bundle[0].tcGen = TCGEN_VECTOR; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name ); - } - } - // - // tcMod <...> - // - else if ( !Q_stricmp( token, "tcMod" ) ) - { - char buffer[1024] = ""; - - while ( 1 ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - break; - strcat( buffer, token ); - strcat( buffer, " " ); - } - - ParseTexMod( buffer, stage ); - - continue; - } - // - // depthmask - // - else if ( !Q_stricmp( token, "depthwrite" ) ) - { - depthMaskBits = GLS_DEPTHMASK_TRUE; - depthMaskExplicit = qtrue; - - continue; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - - // - // if cgen isn't explicitly specified, use either identity or identitylighting - // - if ( stage->rgbGen == CGEN_BAD ) { - if ( blendSrcBits == 0 || - blendSrcBits == GLS_SRCBLEND_ONE || - blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) { - stage->rgbGen = CGEN_IDENTITY_LIGHTING; - } else { - stage->rgbGen = CGEN_IDENTITY; - } - } - - - // - // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending - // - if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && - ( blendDstBits == GLS_DSTBLEND_ZERO ) ) - { - blendDstBits = blendSrcBits = 0; - depthMaskBits = GLS_DEPTHMASK_TRUE; - } - - // decide which agens we can skip - if ( stage->alphaGen == AGEN_IDENTITY ) { - if ( stage->rgbGen == CGEN_IDENTITY - || stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) { - stage->alphaGen = AGEN_SKIP; - } - } - - // - // compute state bits - // - stage->stateBits = depthMaskBits | - blendSrcBits | blendDstBits | - atestBits | - depthFuncBits; - - return qtrue; -} - -/* -=============== -ParseDeform - -deformVertexes wave -deformVertexes normal -deformVertexes move -deformVertexes bulge -deformVertexes projectionShadow -deformVertexes autoSprite -deformVertexes autoSprite2 -deformVertexes text[0-7] -=============== -*/ -static void ParseDeform( char **text ) { - char *token; - deformStage_t *ds; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name ); - return; - } - - if ( shader.numDeforms == MAX_SHADER_DEFORMS ) { - ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name ); - return; - } - - ds = &shader.deforms[ shader.numDeforms ]; - shader.numDeforms++; - - if ( !Q_stricmp( token, "projectionShadow" ) ) { - ds->deformation = DEFORM_PROJECTION_SHADOW; - return; - } - - if ( !Q_stricmp( token, "autosprite" ) ) { - ds->deformation = DEFORM_AUTOSPRITE; - return; - } - - if ( !Q_stricmp( token, "autosprite2" ) ) { - ds->deformation = DEFORM_AUTOSPRITE2; - return; - } - - if ( !Q_stricmpn( token, "text", 4 ) ) { - int n; - - n = token[4] - '0'; - if ( n < 0 || n > 7 ) { - n = 0; - } - ds->deformation = DEFORM_TEXT0 + n; - return; - } - - if ( !Q_stricmp( token, "bulge" ) ) { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeWidth = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeHeight = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeSpeed = atof( token ); - - ds->deformation = DEFORM_BULGE; - return; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - - if ( atof( token ) != 0 ) - { - ds->deformationSpread = 1.0f / atof( token ); - } - else - { - ds->deformationSpread = 100.0f; - ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name ); - } - - ParseWaveForm( text, &ds->deformationWave ); - ds->deformation = DEFORM_WAVE; - return; - } - - if ( !Q_stricmp( token, "normal" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->deformationWave.amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->deformationWave.frequency = atof( token ); - - ds->deformation = DEFORM_NORMALS; - return; - } - - if ( !Q_stricmp( token, "move" ) ) { - int i; - - for ( i = 0 ; i < 3 ; i++ ) { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->moveVector[i] = atof( token ); - } - - ParseWaveForm( text, &ds->deformationWave ); - ds->deformation = DEFORM_MOVE; - return; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name ); -} - - -/* -=============== -ParseSkyParms - -skyParms -=============== -*/ -static void ParseSkyParms( char **text ) { - char *token; - static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; - char pathname[MAX_QPATH]; - int i; - imgFlags_t imgFlags = IMGFLAG_MIPMAP | IMGFLAG_PICMIP; - - if (r_srgb->integer) - imgFlags |= IMGFLAG_SRGB; - - // outerbox - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - if ( strcmp( token, "-" ) ) { - for (i=0 ; i<6 ; i++) { - Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" - , token, suf[i] ); - shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags | IMGFLAG_CLAMPTOEDGE ); - - if ( !shader.sky.outerbox[i] ) { - shader.sky.outerbox[i] = tr.defaultImage; - } - } - } - - // cloudheight - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - shader.sky.cloudHeight = atof( token ); - if ( !shader.sky.cloudHeight ) { - shader.sky.cloudHeight = 512; - } - R_InitSkyTexCoords( shader.sky.cloudHeight ); - - - // innerbox - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - if ( strcmp( token, "-" ) ) { - for (i=0 ; i<6 ; i++) { - Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" - , token, suf[i] ); - shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags ); - if ( !shader.sky.innerbox[i] ) { - shader.sky.innerbox[i] = tr.defaultImage; - } - } - } - - shader.isSky = qtrue; -} - - -/* -================= -ParseSort -================= -*/ -void ParseSort( char **text ) { - char *token; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name ); - return; - } - - if ( !Q_stricmp( token, "portal" ) ) { - shader.sort = SS_PORTAL; - } else if ( !Q_stricmp( token, "sky" ) ) { - shader.sort = SS_ENVIRONMENT; - } else if ( !Q_stricmp( token, "opaque" ) ) { - shader.sort = SS_OPAQUE; - }else if ( !Q_stricmp( token, "decal" ) ) { - shader.sort = SS_DECAL; - } else if ( !Q_stricmp( token, "seeThrough" ) ) { - shader.sort = SS_SEE_THROUGH; - } else if ( !Q_stricmp( token, "banner" ) ) { - shader.sort = SS_BANNER; - } else if ( !Q_stricmp( token, "additive" ) ) { - shader.sort = SS_BLEND1; - } else if ( !Q_stricmp( token, "nearest" ) ) { - shader.sort = SS_NEAREST; - } else if ( !Q_stricmp( token, "underwater" ) ) { - shader.sort = SS_UNDERWATER; - } else { - shader.sort = atof( token ); - } -} - - - -// this table is also present in q3map - -typedef struct { - char *name; - int clearSolid, surfaceFlags, contents; -} infoParm_t; - -infoParm_t infoParms[] = { - // server relevant contents - {"water", 1, 0, CONTENTS_WATER }, - {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging - {"lava", 1, 0, CONTENTS_LAVA }, // very damaging - {"playerclip", 1, 0, CONTENTS_PLAYERCLIP }, - {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP }, - {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc) - {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag - - // utility relevant attributes - {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes - {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces - {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp - {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas - {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas - {"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots - {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots - - {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering - {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map - {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it - {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis - {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter - - // server attributes - {"slick", 0, SURF_SLICK, 0 }, - {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks - {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode - {"ladder", 0, SURF_LADDER, 0 }, - {"nodamage", 0, SURF_NODAMAGE, 0 }, - {"metalsteps", 0, SURF_METALSTEPS,0 }, - {"flesh", 0, SURF_FLESH, 0 }, - {"nosteps", 0, SURF_NOSTEPS, 0 }, - - // drawsurf attributes - {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap) - {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes - {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap - {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights - {"dust", 0, SURF_DUST, 0} // leave a dust trail when walking on this surface -}; - - -/* -=============== -ParseSurfaceParm - -surfaceparm -=============== -*/ -static void ParseSurfaceParm( char **text ) { - char *token; - int numInfoParms = ARRAY_LEN( infoParms ); - int i; - - token = COM_ParseExt( text, qfalse ); - for ( i = 0 ; i < numInfoParms ; i++ ) { - if ( !Q_stricmp( token, infoParms[i].name ) ) { - shader.surfaceFlags |= infoParms[i].surfaceFlags; - shader.contentFlags |= infoParms[i].contents; -#if 0 - if ( infoParms[i].clearSolid ) { - si->contents &= ~CONTENTS_SOLID; - } -#endif - break; - } - } -} - -/* -================= -ParseShader - -The current text pointer is at the explicit text definition of the -shader. Parse it into the global shader variable. Later functions -will optimize it. -================= -*/ -static qboolean ParseShader( char **text ) -{ - char *token; - int s; - - s = 0; - - token = COM_ParseExt( text, qtrue ); - if ( token[0] != '{' ) - { - ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name ); - return qfalse; - } - - while ( 1 ) - { - token = COM_ParseExt( text, qtrue ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name ); - return qfalse; - } - - // end of shader definition - if ( token[0] == '}' ) - { - break; - } - // stage definition - else if ( token[0] == '{' ) - { - if ( s >= MAX_SHADER_STAGES ) { - ri.Printf( PRINT_WARNING, "WARNING: too many stages in shader %s\n", shader.name ); - return qfalse; - } - - if ( !ParseStage( &stages[s], text ) ) - { - return qfalse; - } - stages[s].active = qtrue; - s++; - - continue; - } - // skip stuff that only the QuakeEdRadient needs - else if ( !Q_stricmpn( token, "qer", 3 ) ) { - SkipRestOfLine( text ); - continue; - } - // sun parms - else if ( !Q_stricmp( token, "q3map_sun" ) || !Q_stricmp( token, "q3map_sunExt" ) || !Q_stricmp( token, "q3gl2_sun" ) ) { - float a, b; - qboolean isGL2Sun = qfalse; - - if (!Q_stricmp( token, "q3gl2_sun" ) && r_sunShadows->integer ) - { - isGL2Sun = qtrue; - tr.sunShadows = qtrue; - } - - token = COM_ParseExt( text, qfalse ); - tr.sunLight[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.sunLight[1] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.sunLight[2] = atof( token ); - - VectorNormalize( tr.sunLight ); - - token = COM_ParseExt( text, qfalse ); - a = atof( token ); - VectorScale( tr.sunLight, a, tr.sunLight); - - token = COM_ParseExt( text, qfalse ); - a = atof( token ); - a = a / 180 * M_PI; - - token = COM_ParseExt( text, qfalse ); - b = atof( token ); - b = b / 180 * M_PI; - - tr.sunDirection[0] = cos( a ) * cos( b ); - tr.sunDirection[1] = sin( a ) * cos( b ); - tr.sunDirection[2] = sin( b ); - - if (isGL2Sun) - { - token = COM_ParseExt( text, qfalse ); - tr.mapLightScale = atof(token); - - token = COM_ParseExt( text, qfalse ); - tr.sunShadowScale = atof(token); - } - - SkipRestOfLine( text ); - continue; - } - // tonemap parms - else if ( !Q_stricmp( token, "q3gl2_tonemap" ) ) { - token = COM_ParseExt( text, qfalse ); - tr.toneMinAvgMaxLevel[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.toneMinAvgMaxLevel[1] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.toneMinAvgMaxLevel[2] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - tr.autoExposureMinMax[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.autoExposureMinMax[1] = atof( token ); - - SkipRestOfLine( text ); - continue; - } - else if ( !Q_stricmp( token, "deformVertexes" ) ) { - ParseDeform( text ); - continue; - } - else if ( !Q_stricmp( token, "tesssize" ) ) { - SkipRestOfLine( text ); - continue; - } - else if ( !Q_stricmp( token, "clampTime" ) ) { - token = COM_ParseExt( text, qfalse ); - if (token[0]) { - shader.clampTime = atof(token); - } - } - // skip stuff that only the q3map needs - else if ( !Q_stricmpn( token, "q3map", 5 ) ) { - SkipRestOfLine( text ); - continue; - } - // skip stuff that only q3map or the server needs - else if ( !Q_stricmp( token, "surfaceParm" ) ) { - ParseSurfaceParm( text ); - continue; - } - // no mip maps - else if ( !Q_stricmp( token, "nomipmaps" ) ) - { - shader.noMipMaps = qtrue; - shader.noPicMip = qtrue; - continue; - } - // no picmip adjustment - else if ( !Q_stricmp( token, "nopicmip" ) ) - { - shader.noPicMip = qtrue; - continue; - } - // polygonOffset - else if ( !Q_stricmp( token, "polygonOffset" ) ) - { - shader.polygonOffset = qtrue; - continue; - } - // entityMergable, allowing sprite surfaces from multiple entities - // to be merged into one batch. This is a savings for smoke - // puffs and blood, but can't be used for anything where the - // shader calcs (not the surface function) reference the entity color or scroll - else if ( !Q_stricmp( token, "entityMergable" ) ) - { - shader.entityMergable = qtrue; - continue; - } - // fogParms - else if ( !Q_stricmp( token, "fogParms" ) ) - { - if ( !ParseVector( text, 3, shader.fogParms.color ) ) { - return qfalse; - } - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name ); - continue; - } - shader.fogParms.depthForOpaque = atof( token ); - - // skip any old gradient directions - SkipRestOfLine( text ); - continue; - } - // portal - else if ( !Q_stricmp(token, "portal") ) - { - shader.sort = SS_PORTAL; - shader.isPortal = qtrue; - continue; - } - // skyparms - else if ( !Q_stricmp( token, "skyparms" ) ) - { - ParseSkyParms( text ); - continue; - } - // light determines flaring in q3map, not needed here - else if ( !Q_stricmp(token, "light") ) - { - COM_ParseExt( text, qfalse ); - continue; - } - // cull - else if ( !Q_stricmp( token, "cull") ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) ) - { - shader.cullType = CT_TWO_SIDED; - } - else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) ) - { - shader.cullType = CT_BACK_SIDED; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name ); - } - continue; - } - // sort - else if ( !Q_stricmp( token, "sort" ) ) - { - ParseSort( text ); - continue; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name ); - return qfalse; - } - } - - // - // ignore shaders that don't have any stages, unless it is a sky or fog - // - if ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) { - return qfalse; - } - - shader.explicitlyDefined = qtrue; - - return qtrue; -} - -/* -======================================================================================== - -SHADER OPTIMIZATION AND FOGGING - -======================================================================================== -*/ - -/* -=================== -ComputeStageIteratorFunc - -See if we can use on of the simple fastpath stage functions, -otherwise set to the generic stage function -=================== -*/ -static void ComputeStageIteratorFunc( void ) -{ - shader.optimalStageIteratorFunc = RB_StageIteratorGeneric; - - // - // see if this should go into the sky path - // - if ( shader.isSky ) - { - shader.optimalStageIteratorFunc = RB_StageIteratorSky; - return; - } -} - -/* -=================== -ComputeVertexAttribs - -Check which vertex attributes we only need, so we -don't need to submit/copy all of them. -=================== -*/ -static void ComputeVertexAttribs(void) -{ - int i, stage; - - // dlights always need ATTR_NORMAL - shader.vertexAttribs = ATTR_POSITION | ATTR_NORMAL; - - // portals always need normals, for SurfIsOffscreen() - if (shader.isPortal) - { - shader.vertexAttribs |= ATTR_NORMAL; - } - - if (shader.defaultShader) - { - shader.vertexAttribs |= ATTR_TEXCOORD; - return; - } - - if(shader.numDeforms) - { - for ( i = 0; i < shader.numDeforms; i++) - { - deformStage_t *ds = &shader.deforms[i]; - - switch (ds->deformation) - { - case DEFORM_BULGE: - shader.vertexAttribs |= ATTR_NORMAL | ATTR_TEXCOORD; - break; - - case DEFORM_AUTOSPRITE: - shader.vertexAttribs |= ATTR_NORMAL | ATTR_COLOR; - break; - - case DEFORM_WAVE: - case DEFORM_NORMALS: - case DEFORM_TEXT0: - case DEFORM_TEXT1: - case DEFORM_TEXT2: - case DEFORM_TEXT3: - case DEFORM_TEXT4: - case DEFORM_TEXT5: - case DEFORM_TEXT6: - case DEFORM_TEXT7: - shader.vertexAttribs |= ATTR_NORMAL; - break; - - default: - case DEFORM_NONE: - case DEFORM_MOVE: - case DEFORM_PROJECTION_SHADOW: - case DEFORM_AUTOSPRITE2: - break; - } - } - } - - for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) - { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) - { - break; - } - - if (pStage->glslShaderGroup == tr.lightallShader) - { - shader.vertexAttribs |= ATTR_NORMAL; - -#ifdef USE_VERT_TANGENT_SPACE - if ((pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && !(r_normalMapping->integer == 0 && r_specularMapping->integer == 0)) - { - shader.vertexAttribs |= ATTR_TANGENT; - } -#endif - - switch (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) - { - case LIGHTDEF_USE_LIGHTMAP: - case LIGHTDEF_USE_LIGHT_VERTEX: - shader.vertexAttribs |= ATTR_LIGHTDIRECTION; - break; - default: - break; - } - } - - for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) - { - if ( pStage->bundle[i].image[0] == 0 ) - { - continue; - } - - switch(pStage->bundle[i].tcGen) - { - case TCGEN_TEXTURE: - shader.vertexAttribs |= ATTR_TEXCOORD; - break; - case TCGEN_LIGHTMAP: - shader.vertexAttribs |= ATTR_LIGHTCOORD; - break; - case TCGEN_ENVIRONMENT_MAPPED: - shader.vertexAttribs |= ATTR_NORMAL; - break; - - default: - break; - } - } - - switch(pStage->rgbGen) - { - case CGEN_EXACT_VERTEX: - case CGEN_VERTEX: - case CGEN_EXACT_VERTEX_LIT: - case CGEN_VERTEX_LIT: - case CGEN_ONE_MINUS_VERTEX: - shader.vertexAttribs |= ATTR_COLOR; - break; - - case CGEN_LIGHTING_DIFFUSE: - shader.vertexAttribs |= ATTR_NORMAL; - break; - - default: - break; - } - - switch(pStage->alphaGen) - { - case AGEN_LIGHTING_SPECULAR: - shader.vertexAttribs |= ATTR_NORMAL; - break; - - case AGEN_VERTEX: - case AGEN_ONE_MINUS_VERTEX: - shader.vertexAttribs |= ATTR_COLOR; - break; - - default: - break; - } - } -} - -typedef struct { - int blendA; - int blendB; - - int multitextureEnv; - int multitextureBlend; -} collapse_t; - -static collapse_t collapse[] = { - { 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, 0 }, - - { 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, 0 }, - - { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, - GL_ADD, 0 }, - - { GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, - GL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE }, -#if 0 - { 0, GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA, - GL_DECAL, 0 }, -#endif - { -1 } -}; - -/* -================ -CollapseMultitexture - -Attempt to combine two stages into a single multitexture stage -FIXME: I think modulated add + modulated add collapses incorrectly -================= -*/ -static qboolean CollapseMultitexture( void ) { - int abits, bbits; - int i; - textureBundle_t tmpBundle; - - if ( !qglActiveTextureARB ) { - return qfalse; - } - - // make sure both stages are active - if ( !stages[0].active || !stages[1].active ) { - return qfalse; - } - - // on voodoo2, don't combine different tmus - if ( glConfig.driverType == GLDRV_VOODOO ) { - if ( stages[0].bundle[0].image[0]->TMU == - stages[1].bundle[0].image[0]->TMU ) { - return qfalse; - } - } - - abits = stages[0].stateBits; - bbits = stages[1].stateBits; - - // make sure that both stages have identical state other than blend modes - if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) != - ( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) { - return qfalse; - } - - abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - - // search for a valid multitexture blend function - for ( i = 0; collapse[i].blendA != -1 ; i++ ) { - if ( abits == collapse[i].blendA - && bbits == collapse[i].blendB ) { - break; - } - } - - // nothing found - if ( collapse[i].blendA == -1 ) { - return qfalse; - } - - // GL_ADD is a separate extension - if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) { - return qfalse; - } - - // make sure waveforms have identical parameters - if ( ( stages[0].rgbGen != stages[1].rgbGen ) || - ( stages[0].alphaGen != stages[1].alphaGen ) ) { - return qfalse; - } - - // an add collapse can only have identity colors - if ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) { - return qfalse; - } - - if ( stages[0].rgbGen == CGEN_WAVEFORM ) - { - if ( memcmp( &stages[0].rgbWave, - &stages[1].rgbWave, - sizeof( stages[0].rgbWave ) ) ) - { - return qfalse; - } - } - if ( stages[0].alphaGen == AGEN_WAVEFORM ) - { - if ( memcmp( &stages[0].alphaWave, - &stages[1].alphaWave, - sizeof( stages[0].alphaWave ) ) ) - { - return qfalse; - } - } - - - // make sure that lightmaps are in bundle 1 for 3dfx - if ( stages[0].bundle[0].isLightmap ) - { - tmpBundle = stages[0].bundle[0]; - stages[0].bundle[0] = stages[1].bundle[0]; - stages[0].bundle[1] = tmpBundle; - } - else - { - stages[0].bundle[1] = stages[1].bundle[0]; - } - - // set the new blend state bits - shader.multitextureEnv = collapse[i].multitextureEnv; - stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - stages[0].stateBits |= collapse[i].multitextureBlend; - - // - // move down subsequent shaders - // - memmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) ); - Com_Memset( &stages[MAX_SHADER_STAGES-1], 0, sizeof( stages[0] ) ); - - return qtrue; -} - -static void CollapseStagesToLightall(shaderStage_t *diffuse, - shaderStage_t *normal, shaderStage_t *specular, shaderStage_t *lightmap, - qboolean useLightVector, qboolean useLightVertex, qboolean parallax, qboolean tcgen) -{ - int defs = 0; - - //ri.Printf(PRINT_ALL, "shader %s has diffuse %s", shader.name, diffuse->bundle[0].image[0]->imgName); - - // reuse diffuse, mark others inactive - diffuse->type = ST_GLSL; - - if (lightmap) - { - //ri.Printf(PRINT_ALL, ", lightmap"); - diffuse->bundle[TB_LIGHTMAP] = lightmap->bundle[0]; - defs |= LIGHTDEF_USE_LIGHTMAP; - } - else if (useLightVector) - { - defs |= LIGHTDEF_USE_LIGHT_VECTOR; - } - else if (useLightVertex) - { - defs |= LIGHTDEF_USE_LIGHT_VERTEX; - } - - if (r_deluxeMapping->integer && tr.worldDeluxeMapping && lightmap) - { - //ri.Printf(PRINT_ALL, ", deluxemap"); - diffuse->bundle[TB_DELUXEMAP] = lightmap->bundle[0]; - diffuse->bundle[TB_DELUXEMAP].image[0] = tr.deluxemaps[shader.lightmapIndex]; - } - - if (r_normalMapping->integer) - { - image_t *diffuseImg; - if (normal) - { - //ri.Printf(PRINT_ALL, ", normalmap %s", normal->bundle[0].image[0]->imgName); - diffuse->bundle[TB_NORMALMAP] = normal->bundle[0]; - if (parallax && r_parallaxMapping->integer) - defs |= LIGHTDEF_USE_PARALLAXMAP; - } - else if ((lightmap || useLightVector || useLightVertex) && (diffuseImg = diffuse->bundle[TB_DIFFUSEMAP].image[0])) - { - char normalName[MAX_QPATH]; - image_t *normalImg; - imgFlags_t normalFlags = (diffuseImg->flags & ~(IMGFLAG_GENNORMALMAP | IMGFLAG_SRGB)) | IMGFLAG_NOLIGHTSCALE; - - COM_StripExtension(diffuseImg->imgName, normalName, MAX_QPATH); - Q_strcat(normalName, MAX_QPATH, "_n"); - - normalImg = R_FindImageFile(normalName, IMGTYPE_NORMAL, normalFlags); - - if (normalImg) - { - diffuse->bundle[TB_NORMALMAP] = diffuse->bundle[0]; - diffuse->bundle[TB_NORMALMAP].numImageAnimations = 0; - diffuse->bundle[TB_NORMALMAP].image[0] = normalImg; - - if (parallax && r_parallaxMapping->integer) - defs |= LIGHTDEF_USE_PARALLAXMAP; - } - } - } - - if (r_specularMapping->integer) - { - if (specular) - { - //ri.Printf(PRINT_ALL, ", specularmap %s", specular->bundle[0].image[0]->imgName); - diffuse->bundle[TB_SPECULARMAP] = specular->bundle[0]; - diffuse->materialInfo[0] = specular->materialInfo[0]; - diffuse->materialInfo[1] = specular->materialInfo[1]; - } - } - - if (tcgen || diffuse->bundle[0].numTexMods) - { - defs |= LIGHTDEF_USE_TCGEN_AND_TCMOD; - } - - //ri.Printf(PRINT_ALL, ".\n"); - - diffuse->glslShaderGroup = tr.lightallShader; - diffuse->glslShaderIndex = defs; -} - - -static qboolean CollapseStagesToGLSL(void) -{ - int i, j, numStages; - qboolean skip = qfalse; - - // skip shaders with deforms - if (shader.numDeforms != 0) - { - skip = qtrue; - } - - if (!skip) - { - // if 2+ stages and first stage is lightmap, switch them - // this makes it easier for the later bits to process - if (stages[0].active && stages[0].bundle[0].tcGen == TCGEN_LIGHTMAP && stages[1].active) - { - int blendBits = stages[1].stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - - if (blendBits == (GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO) - || blendBits == (GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR)) - { - int stateBits0 = stages[0].stateBits; - int stateBits1 = stages[1].stateBits; - shaderStage_t swapStage; - - swapStage = stages[0]; - stages[0] = stages[1]; - stages[1] = swapStage; - - stages[0].stateBits = stateBits0; - stages[1].stateBits = stateBits1; - } - } - } - - if (!skip) - { - // scan for shaders that aren't supported - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->adjustColorsForFog) - { - skip = qtrue; - break; - } - - if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP) - { - int blendBits = pStage->stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - - if (blendBits != (GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO) - && blendBits != (GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR)) - { - skip = qtrue; - break; - } - } - - switch(pStage->bundle[0].tcGen) - { - case TCGEN_TEXTURE: - case TCGEN_LIGHTMAP: - case TCGEN_ENVIRONMENT_MAPPED: - case TCGEN_VECTOR: - break; - default: - skip = qtrue; - break; - } - - switch(pStage->alphaGen) - { - case AGEN_LIGHTING_SPECULAR: - case AGEN_PORTAL: - skip = qtrue; - break; - default: - break; - } - } - } - - if (!skip) - { - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - shaderStage_t *diffuse, *normal, *specular, *lightmap; - qboolean parallax, tcgen, diffuselit, vertexlit; - - if (!pStage->active) - continue; - - // skip normal and specular maps - if (pStage->type != ST_COLORMAP) - continue; - - // skip lightmaps - if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP) - continue; - - diffuse = pStage; - normal = NULL; - parallax = qfalse; - specular = NULL; - lightmap = NULL; - - // we have a diffuse map, find matching normal, specular, and lightmap - for (j = i + 1; j < MAX_SHADER_STAGES; j++) - { - shaderStage_t *pStage2 = &stages[j]; - - if (!pStage2->active) - continue; - - switch(pStage2->type) - { - case ST_NORMALMAP: - if (!normal) - { - normal = pStage2; - } - break; - - case ST_NORMALPARALLAXMAP: - if (!normal) - { - normal = pStage2; - parallax = qtrue; - } - break; - - case ST_SPECULARMAP: - if (!specular) - { - specular = pStage2; - } - break; - - case ST_COLORMAP: - if (pStage2->bundle[0].tcGen == TCGEN_LIGHTMAP) - { - lightmap = pStage2; - } - break; - - default: - break; - } - } - - tcgen = qfalse; - if (diffuse->bundle[0].tcGen == TCGEN_ENVIRONMENT_MAPPED - || diffuse->bundle[0].tcGen == TCGEN_LIGHTMAP - || diffuse->bundle[0].tcGen == TCGEN_VECTOR) - { - tcgen = qtrue; - } - - diffuselit = qfalse; - if (diffuse->rgbGen == CGEN_LIGHTING_DIFFUSE) - { - diffuselit = qtrue; - } - - vertexlit = qfalse; - if (diffuse->rgbGen == CGEN_VERTEX_LIT || diffuse->rgbGen == CGEN_EXACT_VERTEX_LIT) - { - vertexlit = qtrue; - } - - CollapseStagesToLightall(diffuse, normal, specular, lightmap, diffuselit, vertexlit, parallax, tcgen); - } - - // deactivate lightmap stages - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP) - { - pStage->active = qfalse; - } - } - } - - // deactivate normal and specular stages - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->type == ST_NORMALMAP) - { - pStage->active = qfalse; - } - - if (pStage->type == ST_NORMALPARALLAXMAP) - { - pStage->active = qfalse; - } - - if (pStage->type == ST_SPECULARMAP) - { - pStage->active = qfalse; - } - } - - // remove inactive stages - numStages = 0; - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - if (!stages[i].active) - continue; - - if (i == numStages) - { - numStages++; - continue; - } - - stages[numStages] = stages[i]; - stages[i].active = qfalse; - numStages++; - } - - if (numStages == i && i >= 2 && CollapseMultitexture()) - numStages--; - - // convert any remaining lightmap stages to a lighting pass with a white texture - // only do this with r_sunlightMode non-zero, as it's only for correct shadows. - if (r_sunlightMode->integer && shader.numDeforms == 0) - { - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->adjustColorsForFog) - continue; - - if (pStage->bundle[TB_DIFFUSEMAP].tcGen == TCGEN_LIGHTMAP) - { - pStage->glslShaderGroup = tr.lightallShader; - pStage->glslShaderIndex = LIGHTDEF_USE_LIGHTMAP; - pStage->bundle[TB_LIGHTMAP] = pStage->bundle[TB_DIFFUSEMAP]; - pStage->bundle[TB_DIFFUSEMAP].image[0] = tr.whiteImage; - pStage->bundle[TB_DIFFUSEMAP].isLightmap = qfalse; - pStage->bundle[TB_DIFFUSEMAP].tcGen = TCGEN_TEXTURE; - } - } - } - - // convert any remaining lightingdiffuse stages to a lighting pass - if (shader.numDeforms == 0) - { - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->adjustColorsForFog) - continue; - - if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE) - { - pStage->glslShaderGroup = tr.lightallShader; - pStage->glslShaderIndex = LIGHTDEF_USE_LIGHT_VECTOR; - - if (pStage->bundle[0].tcGen != TCGEN_TEXTURE || pStage->bundle[0].numTexMods != 0) - pStage->glslShaderIndex |= LIGHTDEF_USE_TCGEN_AND_TCMOD; - } - } - } - - // insert default material info if needed - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->glslShaderGroup != tr.lightallShader) - continue; - - if ((pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) == 0) - continue; - - if (!pStage->bundle[TB_SPECULARMAP].image[0] && r_specularMapping->integer) - { - if (!pStage->materialInfo[0]) - pStage->materialInfo[0] = r_baseSpecular->value; - if (!pStage->materialInfo[1]) - pStage->materialInfo[1] = r_baseGloss->value; - } - } - - return numStages; -} - -/* -============= - -FixRenderCommandList -https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493 -Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated -but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces -to be rendered with bad shaders. To fix this, need to go through all render commands and fix -sortedIndex. -============== -*/ -static void FixRenderCommandList( int newShader ) { - renderCommandList_t *cmdList = &backEndData->commands; - - if( cmdList ) { - const void *curCmd = cmdList->cmds; - - while ( 1 ) { - curCmd = PADP(curCmd, sizeof(void *)); - - switch ( *(const int *)curCmd ) { - case RC_SET_COLOR: - { - const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd; - curCmd = (const void *)(sc_cmd + 1); - break; - } - case RC_STRETCH_PIC: - { - const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd; - curCmd = (const void *)(sp_cmd + 1); - break; - } - case RC_DRAW_SURFS: - { - int i; - drawSurf_t *drawSurf; - shader_t *shader; - int fogNum; - int entityNum; - int dlightMap; - int pshadowMap; - int sortedIndex; - const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd; - - for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) { - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap, &pshadowMap ); - sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1)); - if( sortedIndex >= newShader ) { - sortedIndex++; - drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | ( (int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap; - } - } - curCmd = (const void *)(ds_cmd + 1); - break; - } - case RC_DRAW_BUFFER: - { - const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd; - curCmd = (const void *)(db_cmd + 1); - break; - } - case RC_SWAP_BUFFERS: - { - const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd; - curCmd = (const void *)(sb_cmd + 1); - break; - } - case RC_END_OF_LIST: - default: - return; - } - } - } -} - -/* -============== -SortNewShader - -Positions the most recently created shader in the tr.sortedShaders[] -array so that the shader->sort key is sorted reletive to the other -shaders. - -Sets shader->sortedIndex -============== -*/ -static void SortNewShader( void ) { - int i; - float sort; - shader_t *newShader; - - newShader = tr.shaders[ tr.numShaders - 1 ]; - sort = newShader->sort; - - for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) { - if ( tr.sortedShaders[ i ]->sort <= sort ) { - break; - } - tr.sortedShaders[i+1] = tr.sortedShaders[i]; - tr.sortedShaders[i+1]->sortedIndex++; - } - - // Arnout: fix rendercommandlist - // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493 - FixRenderCommandList( i+1 ); - - newShader->sortedIndex = i+1; - tr.sortedShaders[i+1] = newShader; -} - - -/* -==================== -GeneratePermanentShader -==================== -*/ -static shader_t *GeneratePermanentShader( void ) { - shader_t *newShader; - int i, b; - int size, hash; - - if ( tr.numShaders == MAX_SHADERS ) { - ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n"); - return tr.defaultShader; - } - - newShader = ri.Hunk_Alloc( sizeof( shader_t ), h_low ); - - *newShader = shader; - - if ( shader.sort <= SS_OPAQUE ) { - newShader->fogPass = FP_EQUAL; - } else if ( shader.contentFlags & CONTENTS_FOG ) { - newShader->fogPass = FP_LE; - } - - tr.shaders[ tr.numShaders ] = newShader; - newShader->index = tr.numShaders; - - tr.sortedShaders[ tr.numShaders ] = newShader; - newShader->sortedIndex = tr.numShaders; - - tr.numShaders++; - - for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) { - if ( !stages[i].active ) { - break; - } - newShader->stages[i] = ri.Hunk_Alloc( sizeof( stages[i] ), h_low ); - *newShader->stages[i] = stages[i]; - - for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) { - size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t ); - newShader->stages[i]->bundle[b].texMods = ri.Hunk_Alloc( size, h_low ); - Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size ); - } - } - - SortNewShader(); - - hash = generateHashValue(newShader->name, FILE_HASH_SIZE); - newShader->next = hashTable[hash]; - hashTable[hash] = newShader; - - return newShader; -} - -/* -================= -VertexLightingCollapse - -If vertex lighting is enabled, only render a single -pass, trying to guess which is the correct one to best aproximate -what it is supposed to look like. -================= -*/ -static void VertexLightingCollapse( void ) { - int stage; - shaderStage_t *bestStage; - int bestImageRank; - int rank; - - // if we aren't opaque, just use the first pass - if ( shader.sort == SS_OPAQUE ) { - - // pick the best texture for the single pass - bestStage = &stages[0]; - bestImageRank = -999999; - - for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - rank = 0; - - if ( pStage->bundle[0].isLightmap ) { - rank -= 100; - } - if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) { - rank -= 5; - } - if ( pStage->bundle[0].numTexMods ) { - rank -= 5; - } - if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) { - rank -= 3; - } - - if ( rank > bestImageRank ) { - bestImageRank = rank; - bestStage = pStage; - } - } - - stages[0].bundle[0] = bestStage->bundle[0]; - stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - stages[0].stateBits |= GLS_DEPTHMASK_TRUE; - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - } else { - stages[0].rgbGen = CGEN_EXACT_VERTEX; - } - stages[0].alphaGen = AGEN_SKIP; - } else { - // don't use a lightmap (tesla coils) - if ( stages[0].bundle[0].isLightmap ) { - stages[0] = stages[1]; - } - - // if we were in a cross-fade cgen, hack it to normal - if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH ) - && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH ) - && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - } - - for ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - - Com_Memset( pStage, 0, sizeof( *pStage ) ); - } -} - -/* -========================= -FinishShader - -Returns a freshly allocated shader with all the needed info -from the current global working shader -========================= -*/ -static shader_t *FinishShader( void ) { - int stage; - qboolean hasLightmapStage; - qboolean vertexLightmap; - - hasLightmapStage = qfalse; - vertexLightmap = qfalse; - - // - // set sky stuff appropriate - // - if ( shader.isSky ) { - shader.sort = SS_ENVIRONMENT; - } - - // - // set polygon offset - // - if ( shader.polygonOffset && !shader.sort ) { - shader.sort = SS_DECAL; - } - - // - // set appropriate stage information - // - for ( stage = 0; stage < MAX_SHADER_STAGES; ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - - // check for a missing texture - if ( !pStage->bundle[0].image[0] ) { - ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name ); - pStage->active = qfalse; - stage++; - continue; - } - - // - // ditch this stage if it's detail and detail textures are disabled - // - if ( pStage->isDetail && !r_detailTextures->integer ) - { - int index; - - for(index = stage + 1; index < MAX_SHADER_STAGES; index++) - { - if(!stages[index].active) - break; - } - - if(index < MAX_SHADER_STAGES) - memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage)); - else - { - if(stage + 1 < MAX_SHADER_STAGES) - memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage - 1)); - - Com_Memset(&stages[index - 1], 0, sizeof(*stages)); - } - - continue; - } - - // - // default texture coordinate generation - // - if ( pStage->bundle[0].isLightmap ) { - if ( pStage->bundle[0].tcGen == TCGEN_BAD ) { - pStage->bundle[0].tcGen = TCGEN_LIGHTMAP; - } - hasLightmapStage = qtrue; - } else { - if ( pStage->bundle[0].tcGen == TCGEN_BAD ) { - pStage->bundle[0].tcGen = TCGEN_TEXTURE; - } - } - - - // not a true lightmap but we want to leave existing - // behaviour in place and not print out a warning - //if (pStage->rgbGen == CGEN_VERTEX) { - // vertexLightmap = qtrue; - //} - - - - // - // determine sort order and fog color adjustment - // - if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) && - ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) { - int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS; - int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS; - - // fog color adjustment only works for blend modes that have a contribution - // that aproaches 0 as the modulate values aproach 0 -- - // GL_ONE, GL_ONE - // GL_ZERO, GL_ONE_MINUS_SRC_COLOR - // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA - - // modulate, additive - if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) || - ( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) { - pStage->adjustColorsForFog = ACFF_MODULATE_RGB; - } - // strict blend - else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) - { - pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA; - } - // premultiplied alpha - else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) - { - pStage->adjustColorsForFog = ACFF_MODULATE_RGBA; - } else { - // we can't adjust this one correctly, so it won't be exactly correct in fog - } - - // don't screw with sort order if this is a portal or environment - if ( !shader.sort ) { - // see through item, like a grill or grate - if ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) { - shader.sort = SS_SEE_THROUGH; - } else { - shader.sort = SS_BLEND0; - } - } - } - - stage++; - } - - // there are times when you will need to manually apply a sort to - // opaque alpha tested shaders that have later blend passes - if ( !shader.sort ) { - shader.sort = SS_OPAQUE; - } - - // - // if we are in r_vertexLight mode, never use a lightmap texture - // - if ( stage > 1 && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) { - VertexLightingCollapse(); - hasLightmapStage = qfalse; - } - - // - // look for multitexture potential - // - stage = CollapseStagesToGLSL(); - - if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) { - if (vertexLightmap) { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name ); - } else { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name ); - // Don't set this, it will just add duplicate shaders to the hash - //shader.lightmapIndex = LIGHTMAP_NONE; - } - } - - - // - // compute number of passes - // - shader.numUnfoggedPasses = stage; - - // fogonly shaders don't have any normal passes - if (stage == 0 && !shader.isSky) - shader.sort = SS_FOG; - - // determine which stage iterator function is appropriate - ComputeStageIteratorFunc(); - - // determine which vertex attributes this shader needs - ComputeVertexAttribs(); - - return GeneratePermanentShader(); -} - -//======================================================================================== - -/* -==================== -FindShaderInShaderText - -Scans the combined text description of all the shader files for -the given shader name. - -return NULL if not found - -If found, it will return a valid shader -===================== -*/ -static char *FindShaderInShaderText( const char *shadername ) { - - char *token, *p; - - int i, hash; - - hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH); - - if(shaderTextHashTable[hash]) - { - for (i = 0; shaderTextHashTable[hash][i]; i++) - { - p = shaderTextHashTable[hash][i]; - token = COM_ParseExt(&p, qtrue); - - if(!Q_stricmp(token, shadername)) - return p; - } - } - - p = s_shaderText; - - if ( !p ) { - return NULL; - } - - // look for label - while ( 1 ) { - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - if ( !Q_stricmp( token, shadername ) ) { - return p; - } - else { - // skip the definition - SkipBracedSection( &p, 0 ); - } - } - - return NULL; -} - - -/* -================== -R_FindShaderByName - -Will always return a valid shader, but it might be the -default shader if the real one can't be found. -================== -*/ -shader_t *R_FindShaderByName( const char *name ) { - char strippedName[MAX_QPATH]; - int hash; - shader_t *sh; - - if ( (name==NULL) || (name[0] == 0) ) { - return tr.defaultShader; - } - - COM_StripExtension(name, strippedName, sizeof(strippedName)); - - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - - // - // see if the shader is already loaded - // - for (sh=hashTable[hash]; sh; sh=sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if (Q_stricmp(sh->name, strippedName) == 0) { - // match found - return sh; - } - } - - return tr.defaultShader; -} - - -/* -=============== -R_FindShader - -Will always return a valid shader, but it might be the -default shader if the real one can't be found. - -In the interest of not requiring an explicit shader text entry to -be defined for every single image used in the game, three default -shader behaviors can be auto-created for any image: - -If lightmapIndex == LIGHTMAP_NONE, then the image will have -dynamic diffuse lighting applied to it, as apropriate for most -entity skin surfaces. - -If lightmapIndex == LIGHTMAP_2D, then the image will be used -for 2D rendering unless an explicit shader is found - -If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use -the vertex rgba modulate values, as apropriate for misc_model -pre-lit surfaces. - -Other lightmapIndex values will have a lightmap stage created -and src*dest blending applied with the texture, as apropriate for -most world construction surfaces. - -=============== -*/ -shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) { - char strippedName[MAX_QPATH]; - int i, hash; - char *shaderText; - image_t *image; - shader_t *sh; - - if ( name[0] == 0 ) { - return tr.defaultShader; - } - - // use (fullbright) vertex lighting if the bsp file doesn't have - // lightmaps - if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) { - lightmapIndex = LIGHTMAP_BY_VERTEX; - } else if ( lightmapIndex < LIGHTMAP_2D ) { - // negative lightmap indexes cause stray pointers (think tr.lightmaps[lightmapIndex]) - ri.Printf( PRINT_WARNING, "WARNING: shader '%s' has invalid lightmap index of %d\n", name, lightmapIndex ); - lightmapIndex = LIGHTMAP_BY_VERTEX; - } - - COM_StripExtension(name, strippedName, sizeof(strippedName)); - - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - - // - // see if the shader is already loaded - // - for (sh = hashTable[hash]; sh; sh = sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) && - !Q_stricmp(sh->name, strippedName)) { - // match found - return sh; - } - } - - // clear the global shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - Q_strncpyz(shader.name, strippedName, sizeof(shader.name)); - shader.lightmapIndex = lightmapIndex; - for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) { - stages[i].bundle[0].texMods = texMods[i]; - } - - // - // attempt to define shader from an explicit parameter file - // - shaderText = FindShaderInShaderText( strippedName ); - if ( shaderText ) { - // enable this when building a pak file to get a global list - // of all explicit shaders - if ( r_printShaders->integer ) { - ri.Printf( PRINT_ALL, "*SHADER* %s\n", name ); - } - - if ( !ParseShader( &shaderText ) ) { - // had errors, so use default shader - shader.defaultShader = qtrue; - } - sh = FinishShader(); - return sh; - } - - - // - // if not defined in the in-memory shader descriptions, - // look for a single supported image file - // - { - imgFlags_t flags; - - flags = IMGFLAG_NONE; - - if (r_srgb->integer) - flags |= IMGFLAG_SRGB; - - if (mipRawImage) - { - flags |= IMGFLAG_MIPMAP | IMGFLAG_PICMIP; - - if (r_genNormalMaps->integer) - flags |= IMGFLAG_GENNORMALMAP; - } - else - { - flags |= IMGFLAG_CLAMPTOEDGE; - } - - image = R_FindImageFile( name, IMGTYPE_COLORALPHA, flags ); - if ( !image ) { - ri.Printf( PRINT_DEVELOPER, "Couldn't find image file for shader %s\n", name ); - shader.defaultShader = qtrue; - return FinishShader(); - } - } - - // - // create the default shading commands - // - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - // dynamic colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { - // explicit colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_EXACT_VERTEX; - stages[0].alphaGen = AGEN_SKIP; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { - // GUI elements - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_VERTEX; - stages[0].alphaGen = AGEN_VERTEX; - stages[0].stateBits = GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { - // fullbright level - stages[0].bundle[0].image[0] = tr.whiteImage; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } else { - // two pass lightmap - stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - stages[0].bundle[0].isLightmap = qtrue; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation - // for identitylight - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } - - return FinishShader(); -} - - -qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage) { - int i, hash; - shader_t *sh; - - hash = generateHashValue(name, FILE_HASH_SIZE); - - // probably not necessary since this function - // only gets called from tr_font.c with lightmapIndex == LIGHTMAP_2D - // but better safe than sorry. - if ( lightmapIndex >= tr.numLightmaps ) { - lightmapIndex = LIGHTMAP_WHITEIMAGE; - } - - // - // see if the shader is already loaded - // - for (sh=hashTable[hash]; sh; sh=sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) && - // index by name - !Q_stricmp(sh->name, name)) { - // match found - return sh->index; - } - } - - // clear the global shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - Q_strncpyz(shader.name, name, sizeof(shader.name)); - shader.lightmapIndex = lightmapIndex; - for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) { - stages[i].bundle[0].texMods = texMods[i]; - } - - // - // create the default shading commands - // - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - // dynamic colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { - // explicit colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_EXACT_VERTEX; - stages[0].alphaGen = AGEN_SKIP; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { - // GUI elements - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_VERTEX; - stages[0].alphaGen = AGEN_VERTEX; - stages[0].stateBits = GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { - // fullbright level - stages[0].bundle[0].image[0] = tr.whiteImage; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } else { - // two pass lightmap - stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - stages[0].bundle[0].isLightmap = qtrue; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation - // for identitylight - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } - - sh = FinishShader(); - return sh->index; -} - - -/* -==================== -RE_RegisterShader - -This is the exported shader entry point for the rest of the system -It will always return an index that will be valid. - -This should really only be used for explicit shaders, because there is no -way to ask for different implicit lighting modes (vertex, lightmap, etc) -==================== -*/ -qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, lightmapIndex, qtrue ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - - -/* -==================== -RE_RegisterShader - -This is the exported shader entry point for the rest of the system -It will always return an index that will be valid. - -This should really only be used for explicit shaders, because there is no -way to ask for different implicit lighting modes (vertex, lightmap, etc) -==================== -*/ -qhandle_t RE_RegisterShader( const char *name ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, LIGHTMAP_2D, qtrue ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - - -/* -==================== -RE_RegisterShaderNoMip - -For menu graphics that should never be picmiped -==================== -*/ -qhandle_t RE_RegisterShaderNoMip( const char *name ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, LIGHTMAP_2D, qfalse ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - -/* -==================== -R_GetShaderByHandle - -When a handle is passed in by another module, this range checks -it and returns a valid (possibly default) shader_t to be used internally. -==================== -*/ -shader_t *R_GetShaderByHandle( qhandle_t hShader ) { - if ( hShader < 0 ) { - ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); - return tr.defaultShader; - } - if ( hShader >= tr.numShaders ) { - ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); - return tr.defaultShader; - } - return tr.shaders[hShader]; -} - -/* -=============== -R_ShaderList_f - -Dump information on all valid shaders to the console -A second parameter will cause it to print in sorted order -=============== -*/ -void R_ShaderList_f (void) { - int i; - int count; - shader_t *shader; - - ri.Printf (PRINT_ALL, "-----------------------\n"); - - count = 0; - for ( i = 0 ; i < tr.numShaders ; i++ ) { - if ( ri.Cmd_Argc() > 1 ) { - shader = tr.sortedShaders[i]; - } else { - shader = tr.shaders[i]; - } - - ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses ); - - if (shader->lightmapIndex >= 0 ) { - ri.Printf (PRINT_ALL, "L "); - } else { - ri.Printf (PRINT_ALL, " "); - } - if ( shader->multitextureEnv == GL_ADD ) { - ri.Printf( PRINT_ALL, "MT(a) " ); - } else if ( shader->multitextureEnv == GL_MODULATE ) { - ri.Printf( PRINT_ALL, "MT(m) " ); - } else if ( shader->multitextureEnv == GL_DECAL ) { - ri.Printf( PRINT_ALL, "MT(d) " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - if ( shader->explicitlyDefined ) { - ri.Printf( PRINT_ALL, "E " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - - if ( shader->optimalStageIteratorFunc == RB_StageIteratorGeneric ) { - ri.Printf( PRINT_ALL, "gen " ); - } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorSky ) { - ri.Printf( PRINT_ALL, "sky " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - - if ( shader->defaultShader ) { - ri.Printf (PRINT_ALL, ": %s (DEFAULTED)\n", shader->name); - } else { - ri.Printf (PRINT_ALL, ": %s\n", shader->name); - } - count++; - } - ri.Printf (PRINT_ALL, "%i total shaders\n", count); - ri.Printf (PRINT_ALL, "------------------\n"); -} - -/* -==================== -ScanAndLoadShaderFiles - -Finds and loads all .shader files, combining them into -a single large text block that can be scanned for shader names -===================== -*/ -#define MAX_SHADER_FILES 4096 -static void ScanAndLoadShaderFiles( void ) -{ - char **shaderFiles; - char *buffers[MAX_SHADER_FILES]; - char *p; - int numShaderFiles; - int i; - char *oldp, *token, *hashMem, *textEnd; - int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size; - char shaderName[MAX_QPATH]; - int shaderLine; - - long sum = 0, summand; - // scan for shader files - shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles ); - - if ( !shaderFiles || !numShaderFiles ) - { - ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" ); - return; - } - - if ( numShaderFiles > MAX_SHADER_FILES ) { - numShaderFiles = MAX_SHADER_FILES; - } - - // load and parse shader files - for ( i = 0; i < numShaderFiles; i++ ) - { - char filename[MAX_QPATH]; - - // look for a .mtr file first - { - char *ext; - Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] ); - if ( (ext = strrchr(filename, '.')) ) - { - strcpy(ext, ".mtr"); - } - - if ( ri.FS_ReadFile( filename, NULL ) <= 0 ) - { - Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] ); - } - } - - ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename ); - summand = ri.FS_ReadFile( filename, (void **)&buffers[i] ); - - if ( !buffers[i] ) - ri.Error( ERR_DROP, "Couldn't load %s", filename ); - - // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders. - p = buffers[i]; - COM_BeginParseSession(filename); - while(1) - { - token = COM_ParseExt(&p, qtrue); - - if(!*token) - break; - - Q_strncpyz(shaderName, token, sizeof(shaderName)); - shaderLine = COM_GetCurrentParseLine(); - - token = COM_ParseExt(&p, qtrue); - if(token[0] != '{' || token[1] != '\0') - { - ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing opening brace", - filename, shaderName, shaderLine); - if (token[0]) - { - ri.Printf(PRINT_WARNING, " (found \"%s\" on line %d)", token, COM_GetCurrentParseLine()); - } - ri.Printf(PRINT_WARNING, ".\n"); - ri.FS_FreeFile(buffers[i]); - buffers[i] = NULL; - break; - } - - if(!SkipBracedSection(&p, 1)) - { - ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n", - filename, shaderName, shaderLine); - ri.FS_FreeFile(buffers[i]); - buffers[i] = NULL; - break; - } - } - - - if (buffers[i]) - sum += summand; - } - - // build single large buffer - s_shaderText = ri.Hunk_Alloc( sum + numShaderFiles*2, h_low ); - s_shaderText[ 0 ] = '\0'; - textEnd = s_shaderText; - - // free in reverse order, so the temp files are all dumped - for ( i = numShaderFiles - 1; i >= 0 ; i-- ) - { - if ( !buffers[i] ) - continue; - - strcat( textEnd, buffers[i] ); - strcat( textEnd, "\n" ); - textEnd += strlen( textEnd ); - ri.FS_FreeFile( buffers[i] ); - } - - COM_Compress( s_shaderText ); - - // free up memory - ri.FS_FreeFileList( shaderFiles ); - - Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes)); - size = 0; - - p = s_shaderText; - // look for shader names - while ( 1 ) { - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - hash = generateHashValue(token, MAX_SHADERTEXT_HASH); - shaderTextHashTableSizes[hash]++; - size++; - SkipBracedSection(&p, 0); - } - - size += MAX_SHADERTEXT_HASH; - - hashMem = ri.Hunk_Alloc( size * sizeof(char *), h_low ); - - for (i = 0; i < MAX_SHADERTEXT_HASH; i++) { - shaderTextHashTable[i] = (char **) hashMem; - hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *)); - } - - Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes)); - - p = s_shaderText; - // look for shader names - while ( 1 ) { - oldp = p; - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - hash = generateHashValue(token, MAX_SHADERTEXT_HASH); - shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp; - - SkipBracedSection(&p, 0); - } - - return; - -} - - -/* -==================== -CreateInternalShaders -==================== -*/ -static void CreateInternalShaders( void ) { - tr.numShaders = 0; - - // init the default shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - - Q_strncpyz( shader.name, "", sizeof( shader.name ) ); - - shader.lightmapIndex = LIGHTMAP_NONE; - stages[0].bundle[0].image[0] = tr.defaultImage; - stages[0].active = qtrue; - stages[0].stateBits = GLS_DEFAULT; - tr.defaultShader = FinishShader(); - - // shadow shader is just a marker - Q_strncpyz( shader.name, "", sizeof( shader.name ) ); - shader.sort = SS_STENCIL_SHADOW; - tr.shadowShader = FinishShader(); -} - -static void CreateExternalShaders( void ) { - tr.projectionShadowShader = R_FindShader( "projectionShadow", LIGHTMAP_NONE, qtrue ); - tr.flareShader = R_FindShader( "flareShader", LIGHTMAP_NONE, qtrue ); - - // Hack to make fogging work correctly on flares. Fog colors are calculated - // in tr_flare.c already. - if(!tr.flareShader->defaultShader) - { - int index; - - for(index = 0; index < tr.flareShader->numUnfoggedPasses; index++) - { - tr.flareShader->stages[index]->adjustColorsForFog = ACFF_NONE; - tr.flareShader->stages[index]->stateBits |= GLS_DEPTHTEST_DISABLE; - } - } - - tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue ); - - tr.sunFlareShader = R_FindShader( "gfx/2d/sunflare", LIGHTMAP_NONE, qtrue); - - // HACK: if sunflare is missing, make one using the flare image or dlight image - if (tr.sunFlareShader->defaultShader) - { - image_t *image; - - if (!tr.flareShader->defaultShader && tr.flareShader->stages[0] && tr.flareShader->stages[0]->bundle[0].image[0]) - image = tr.flareShader->stages[0]->bundle[0].image[0]; - else - image = tr.dlightImage; - - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - - Q_strncpyz( shader.name, "gfx/2d/sunflare", sizeof( shader.name ) ); - - shader.lightmapIndex = LIGHTMAP_NONE; - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].stateBits = GLS_DEFAULT; - tr.sunFlareShader = FinishShader(); - } - -} - -/* -================== -R_InitShaders -================== -*/ -void R_InitShaders( void ) { - ri.Printf( PRINT_ALL, "Initializing Shaders\n" ); - - Com_Memset(hashTable, 0, sizeof(hashTable)); - - CreateInternalShaders(); - - ScanAndLoadShaderFiles(); - - CreateExternalShaders(); -} diff --git a/code/renderergl2/tr_shadows.c b/code/renderergl2/tr_shadows.c deleted file mode 100644 index f412b00d3e..0000000000 --- a/code/renderergl2/tr_shadows.c +++ /dev/null @@ -1,343 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - - -/* - - for a projection shadow: - - point[x] += light vector * ( z - shadow plane ) - point[y] += - point[z] = shadow plane - - 1 0 light[x] / light[z] - -*/ - -typedef struct { - int i2; - int facing; -} edgeDef_t; - -#define MAX_EDGE_DEFS 32 - -static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS]; -static int numEdgeDefs[SHADER_MAX_VERTEXES]; -static int facing[SHADER_MAX_INDEXES/3]; - -void R_AddEdgeDef( int i1, int i2, int facing ) { - int c; - - c = numEdgeDefs[ i1 ]; - if ( c == MAX_EDGE_DEFS ) { - return; // overflow - } - edgeDefs[ i1 ][ c ].i2 = i2; - edgeDefs[ i1 ][ c ].facing = facing; - - numEdgeDefs[ i1 ]++; -} - -void R_RenderShadowEdges( void ) { - int i; - -#if 0 - int numTris; - - // dumb way -- render every triangle's edges - numTris = tess.numIndexes / 3; - - for ( i = 0 ; i < numTris ; i++ ) { - int i1, i2, i3; - - if ( !facing[i] ) { - continue; - } - - i1 = tess.indexes[ i*3 + 0 ]; - i2 = tess.indexes[ i*3 + 1 ]; - i3 = tess.indexes[ i*3 + 2 ]; - - qglBegin( GL_TRIANGLE_STRIP ); - qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i3 ] ); - qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); - qglEnd(); - } -#else - int c, c2; - int j, k; - int i2; - int c_edges, c_rejected; - int hit[2]; - - // an edge is NOT a silhouette edge if its face doesn't face the light, - // or if it has a reverse paired edge that also faces the light. - // A well behaved polyhedron would have exactly two faces for each edge, - // but lots of models have dangling edges or overfanned edges - c_edges = 0; - c_rejected = 0; - - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - c = numEdgeDefs[ i ]; - for ( j = 0 ; j < c ; j++ ) { - if ( !edgeDefs[ i ][ j ].facing ) { - continue; - } - - hit[0] = 0; - hit[1] = 0; - - i2 = edgeDefs[ i ][ j ].i2; - c2 = numEdgeDefs[ i2 ]; - for ( k = 0 ; k < c2 ; k++ ) { - if ( edgeDefs[ i2 ][ k ].i2 == i ) { - hit[ edgeDefs[ i2 ][ k ].facing ]++; - } - } - - // if it doesn't share the edge with another front facing - // triangle, it is a sil edge - if ( hit[ 1 ] == 0 ) { - qglBegin( GL_TRIANGLE_STRIP ); - qglVertex3fv( tess.xyz[ i ] ); - qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); - qglEnd(); - c_edges++; - } else { - c_rejected++; - } - } - } -#endif -} - -/* -================= -RB_ShadowTessEnd - -triangleFromEdge[ v1 ][ v2 ] - - - set triangle from edge( v1, v2, tri ) - if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { - } -================= -*/ -void RB_ShadowTessEnd( void ) { - int i; - int numTris; - vec3_t lightDir; - GLboolean rgba[4]; - - // we can only do this if we have enough space in the vertex buffers - if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { - return; - } - - if ( glConfig.stencilBits < 4 ) { - return; - } - - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); - - // project vertexes away from light direction - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); - } - - // decide which triangles face the light - Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes ); - - numTris = tess.numIndexes / 3; - for ( i = 0 ; i < numTris ; i++ ) { - int i1, i2, i3; - vec3_t d1, d2, normal; - float *v1, *v2, *v3; - float d; - - i1 = tess.indexes[ i*3 + 0 ]; - i2 = tess.indexes[ i*3 + 1 ]; - i3 = tess.indexes[ i*3 + 2 ]; - - v1 = tess.xyz[ i1 ]; - v2 = tess.xyz[ i2 ]; - v3 = tess.xyz[ i3 ]; - - VectorSubtract( v2, v1, d1 ); - VectorSubtract( v3, v1, d2 ); - CrossProduct( d1, d2, normal ); - - d = DotProduct( normal, lightDir ); - if ( d > 0 ) { - facing[ i ] = 1; - } else { - facing[ i ] = 0; - } - - // create the edges - R_AddEdgeDef( i1, i2, facing[ i ] ); - R_AddEdgeDef( i2, i3, facing[ i ] ); - R_AddEdgeDef( i3, i1, facing[ i ] ); - } - - // draw the silhouette edges - - GL_Bind( tr.whiteImage ); - qglEnable( GL_CULL_FACE ); - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - qglColor3f( 0.2f, 0.2f, 0.2f ); - - // don't write to the color buffer - qglGetBooleanv(GL_COLOR_WRITEMASK, rgba); - qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); - - qglEnable( GL_STENCIL_TEST ); - qglStencilFunc( GL_ALWAYS, 1, 255 ); - - // mirrors have the culling order reversed - if ( backEnd.viewParms.isMirror ) { - qglCullFace( GL_FRONT ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); - - R_RenderShadowEdges(); - - qglCullFace( GL_BACK ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); - - R_RenderShadowEdges(); - } else { - qglCullFace( GL_BACK ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); - - R_RenderShadowEdges(); - - qglCullFace( GL_FRONT ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); - - R_RenderShadowEdges(); - } - - - // reenable writing to the color buffer - qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); -} - - -/* -================= -RB_ShadowFinish - -Darken everything that is is a shadow volume. -We have to delay this until everything has been shadowed, -because otherwise shadows from different body parts would -overlap and double darken. -================= -*/ -void RB_ShadowFinish( void ) { - if ( r_shadows->integer != 2 ) { - return; - } - if ( glConfig.stencilBits < 4 ) { - return; - } - qglEnable( GL_STENCIL_TEST ); - qglStencilFunc( GL_NOTEQUAL, 0, 255 ); - - qglDisable (GL_CLIP_PLANE0); - qglDisable (GL_CULL_FACE); - - GL_Bind( tr.whiteImage ); - - qglLoadIdentity (); - - qglColor3f( 0.6f, 0.6f, 0.6f ); - GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); - -// qglColor3f( 1, 0, 0 ); -// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - - qglBegin( GL_QUADS ); - qglVertex3f( -100, 100, -10 ); - qglVertex3f( 100, 100, -10 ); - qglVertex3f( 100, -100, -10 ); - qglVertex3f( -100, -100, -10 ); - qglEnd (); - - qglColor4f(1,1,1,1); - qglDisable( GL_STENCIL_TEST ); -} - - -/* -================= -RB_ProjectionShadowDeform - -================= -*/ -void RB_ProjectionShadowDeform( void ) { - float *xyz; - int i; - float h; - vec3_t ground; - vec3_t light; - float groundDist; - float d; - vec3_t lightDir; - - xyz = ( float * ) tess.xyz; - - ground[0] = backEnd.or.axis[0][2]; - ground[1] = backEnd.or.axis[1][2]; - ground[2] = backEnd.or.axis[2][2]; - - groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane; - - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); - d = DotProduct( lightDir, ground ); - // don't let the shadows get too long or go negative - if ( d < 0.5 ) { - VectorMA( lightDir, (0.5 - d), ground, lightDir ); - d = DotProduct( lightDir, ground ); - } - d = 1.0 / d; - - light[0] = lightDir[0] * d; - light[1] = lightDir[1] * d; - light[2] = lightDir[2] * d; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) { - h = DotProduct( xyz, ground ) + groundDist; - - xyz[0] -= light[0] * h; - xyz[1] -= light[1] * h; - xyz[2] -= light[2] * h; - } -} diff --git a/code/renderergl2/tr_sky.c b/code/renderergl2/tr_sky.c deleted file mode 100644 index 6a22031889..0000000000 --- a/code/renderergl2/tr_sky.c +++ /dev/null @@ -1,912 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_sky.c -#include "tr_local.h" - -#define SKY_SUBDIVISIONS 8 -#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2) - -static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; -static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; - -/* -=================================================================================== - -POLYGON TO BOX SIDE PROJECTION - -=================================================================================== -*/ - -static vec3_t sky_clip[6] = -{ - {1,1,0}, - {1,-1,0}, - {0,-1,1}, - {0,1,1}, - {1,0,1}, - {-1,0,1} -}; - -static float sky_mins[2][6], sky_maxs[2][6]; -static float sky_min, sky_max; - -/* -================ -AddSkyPolygon -================ -*/ -static void AddSkyPolygon (int nump, vec3_t vecs) -{ - int i,j; - vec3_t v, av; - float s, t, dv; - int axis; - float *vp; - // s = [0]/[2], t = [1]/[2] - static int vec_to_st[6][3] = - { - {-2,3,1}, - {2,3,-1}, - - {1,3,2}, - {-1,3,-2}, - - {-2,-1,3}, - {-2,1,-3} - - // {-1,2,3}, - // {1,2,-3} - }; - - // decide which face it maps to - VectorCopy (vec3_origin, v); - for (i=0, vp=vecs ; i av[1] && av[0] > av[2]) - { - if (v[0] < 0) - axis = 1; - else - axis = 0; - } - else if (av[1] > av[2] && av[1] > av[0]) - { - if (v[1] < 0) - axis = 3; - else - axis = 2; - } - else - { - if (v[2] < 0) - axis = 5; - else - axis = 4; - } - - // project new texture coords - for (i=0 ; i 0) - dv = vecs[j - 1]; - else - dv = -vecs[-j - 1]; - if (dv < 0.001) - continue; // don't divide by zero - j = vec_to_st[axis][0]; - if (j < 0) - s = -vecs[-j -1] / dv; - else - s = vecs[j-1] / dv; - j = vec_to_st[axis][1]; - if (j < 0) - t = -vecs[-j -1] / dv; - else - t = vecs[j-1] / dv; - - if (s < sky_mins[0][axis]) - sky_mins[0][axis] = s; - if (t < sky_mins[1][axis]) - sky_mins[1][axis] = t; - if (s > sky_maxs[0][axis]) - sky_maxs[0][axis] = s; - if (t > sky_maxs[1][axis]) - sky_maxs[1][axis] = t; - } -} - -#define ON_EPSILON 0.1f // point on plane side epsilon -#define MAX_CLIP_VERTS 64 -/* -================ -ClipSkyPolygon -================ -*/ -static void ClipSkyPolygon (int nump, vec3_t vecs, int stage) -{ - float *norm; - float *v; - qboolean front, back; - float d, e; - float dists[MAX_CLIP_VERTS]; - int sides[MAX_CLIP_VERTS]; - vec3_t newv[2][MAX_CLIP_VERTS]; - int newc[2]; - int i, j; - - if (nump > MAX_CLIP_VERTS-2) - ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); - if (stage == 6) - { // fully clipped, so draw it - AddSkyPolygon (nump, vecs); - return; - } - - front = back = qfalse; - norm = sky_clip[stage]; - for (i=0, v = vecs ; i ON_EPSILON) - { - front = qtrue; - sides[i] = SIDE_FRONT; - } - else if (d < -ON_EPSILON) - { - back = qtrue; - sides[i] = SIDE_BACK; - } - else - sides[i] = SIDE_ON; - dists[i] = d; - } - - if (!front || !back) - { // not clipped - ClipSkyPolygon (nump, vecs, stage+1); - return; - } - - // clip it - sides[i] = sides[0]; - dists[i] = dists[0]; - VectorCopy (vecs, (vecs+(i*3)) ); - newc[0] = newc[1] = 0; - - for (i=0, v = vecs ; inumIndexes; i += 3 ) - { - for (j = 0 ; j < 3 ; j++) - { - VectorSubtract( input->xyz[input->indexes[i+j]], - backEnd.viewParms.or.origin, - p[j] ); - } - ClipSkyPolygon( 3, p[0], 0 ); - } -} - -/* -=================================================================================== - -CLOUD VERTEX GENERATION - -=================================================================================== -*/ - -/* -** MakeSkyVec -** -** Parms: s, t range from -1 to 1 -*/ -static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ ) -{ - // 1 = s, 2 = t, 3 = 2048 - static int st_to_vec[6][3] = - { - {3,-1,2}, - {-3,1,2}, - - {1,3,2}, - {-1,-3,2}, - - {-2,-1,3}, // 0 degrees yaw, look straight up - {2,-1,-3} // look straight down - }; - - vec3_t b; - int j, k; - float boxSize; - - boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - b[0] = s*boxSize; - b[1] = t*boxSize; - b[2] = boxSize; - - for (j=0 ; j<3 ; j++) - { - k = st_to_vec[axis][j]; - if (k < 0) - { - outXYZ[j] = -b[-k - 1]; - } - else - { - outXYZ[j] = b[k - 1]; - } - } - - // avoid bilerp seam - s = (s+1)*0.5; - t = (t+1)*0.5; - if (s < sky_min) - { - s = sky_min; - } - else if (s > sky_max) - { - s = sky_max; - } - - if (t < sky_min) - { - t = sky_min; - } - else if (t > sky_max) - { - t = sky_max; - } - - t = 1.0 - t; - - - if ( outSt ) - { - outSt[0] = s; - outSt[1] = t; - } -} - -static int sky_texorder[6] = {0,2,1,3,4,5}; -static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; -static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; - -static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] ) -{ - int s, t; - int firstVertex = tess.numVertexes; - //int firstIndex = tess.numIndexes; - int minIndex = tess.minIndex; - int maxIndex = tess.maxIndex; - vec4_t color; - - //tess.numVertexes = 0; - //tess.numIndexes = 0; - tess.firstIndex = tess.numIndexes; - - GL_Bind( image ); - GL_Cull( CT_TWO_SIDED ); - - for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - tess.xyz[tess.numVertexes][0] = s_skyPoints[t][s][0]; - tess.xyz[tess.numVertexes][1] = s_skyPoints[t][s][1]; - tess.xyz[tess.numVertexes][2] = s_skyPoints[t][s][2]; - tess.xyz[tess.numVertexes][3] = 1.0; - - tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; - tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; - - tess.numVertexes++; - - if(tess.numVertexes >= SHADER_MAX_VERTEXES) - { - ri.Error(ERR_DROP, "SHADER_MAX_VERTEXES hit in DrawSkySideVBO()"); - } - } - } - - for ( t = 0; t < maxs[1] - mins[1]; t++ ) - { - for ( s = 0; s < maxs[0] - mins[0]; s++ ) - { - if (tess.numIndexes + 6 >= SHADER_MAX_INDEXES) - { - ri.Error(ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySideVBO()"); - } - - tess.indexes[tess.numIndexes++] = s + t * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex; - - tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = (s + 1) + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; - } - } - - tess.minIndex = firstVertex; - tess.maxIndex = tess.numVertexes; - - // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function - RB_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD); -/* - { - shaderProgram_t *sp = &tr.textureColorShader; - - GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - color[0] = - color[1] = - color[2] = tr.identityLight; - color[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); - } -*/ - { - shaderProgram_t *sp = &tr.lightallShader[0]; - vec4_t vector; - - GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - color[0] = - color[1] = - color[2] = (r_softOverbright->integer ? 1.0 : tr.identityLight) * backEnd.refdef.colorScale; - color[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color); - - color[0] = - color[1] = - color[2] = - color[3] = 0.0f; - GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, color); - - VectorSet4(vector, 1.0, 0.0, 0.0, 1.0); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector); - - VectorSet4(vector, 0.0, 0.0, 0.0, 0.0); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector); - } - - R_DrawElementsVBO(tess.numIndexes - tess.firstIndex, tess.firstIndex, tess.minIndex, tess.maxIndex); - - //qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(glIndex_t))); - - //R_BindNullVBO(); - //R_BindNullIBO(); - - tess.numIndexes = tess.firstIndex; - tess.numVertexes = firstVertex; - tess.firstIndex = 0; - tess.minIndex = minIndex; - tess.maxIndex = maxIndex; -} - -static void DrawSkyBox( shader_t *shader ) -{ - int i; - - sky_min = 0; - sky_max = 1; - - Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) ); - - for (i=0 ; i<6 ; i++) - { - int sky_mins_subd[2], sky_maxs_subd[2]; - int s, t; - - sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - - if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || - ( sky_mins[1][i] >= sky_maxs[1][i] ) ) - { - continue; - } - - sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS; - sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS; - sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS; - sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS; - - if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; - - if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; - - // - // iterate through the subdivisions - // - for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - s_skyTexCoords[t][s], - s_skyPoints[t][s] ); - } - } - - DrawSkySide( shader->sky.outerbox[sky_texorder[i]], - sky_mins_subd, - sky_maxs_subd ); - } - -} - -static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes ) -{ - int s, t; - int vertexStart = tess.numVertexes; - int tHeight, sWidth; - - tHeight = maxs[1] - mins[1] + 1; - sWidth = maxs[0] - mins[0] + 1; - - for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; - tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; - - tess.numVertexes++; - - if ( tess.numVertexes >= SHADER_MAX_VERTEXES ) - { - ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()" ); - } - } - } - - // only add indexes for one pass, otherwise it would draw multiple times for each pass - if ( addIndexes ) { - for ( t = 0; t < tHeight-1; t++ ) - { - for ( s = 0; s < sWidth-1; s++ ) - { - tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); - tess.numIndexes++; - - tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); - tess.numIndexes++; - } - } - } -} - -static void FillCloudBox( const shader_t *shader, int stage ) -{ - int i; - - for ( i =0; i < 6; i++ ) - { - int sky_mins_subd[2], sky_maxs_subd[2]; - int s, t; - float MIN_T; - - if ( 1 ) // FIXME? shader->sky.fullClouds ) - { - MIN_T = -HALF_SKY_SUBDIVISIONS; - - // still don't want to draw the bottom, even if fullClouds - if ( i == 5 ) - continue; - } - else - { - switch( i ) - { - case 0: - case 1: - case 2: - case 3: - MIN_T = -1; - break; - case 5: - // don't draw clouds beneath you - continue; - case 4: // top - default: - MIN_T = -HALF_SKY_SUBDIVISIONS; - break; - } - } - - sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - - if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || - ( sky_mins[1][i] >= sky_maxs[1][i] ) ) - { - continue; - } - - sky_mins_subd[0] = ri.ftol(sky_mins[0][i] * HALF_SKY_SUBDIVISIONS); - sky_mins_subd[1] = ri.ftol(sky_mins[1][i] * HALF_SKY_SUBDIVISIONS); - sky_maxs_subd[0] = ri.ftol(sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS); - sky_maxs_subd[1] = ri.ftol(sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS); - - if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_mins_subd[1] < MIN_T ) - sky_mins_subd[1] = MIN_T; - else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; - - if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_maxs_subd[1] < MIN_T ) - sky_maxs_subd[1] = MIN_T; - else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; - - // - // iterate through the subdivisions - // - for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - NULL, - s_skyPoints[t][s] ); - - s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0]; - s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1]; - } - } - - // only add indexes for first stage - FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) ); - } -} - -/* -** R_BuildCloudData -*/ -void R_BuildCloudData( shaderCommands_t *input ) -{ - int i; - shader_t *shader; - - shader = input->shader; - - assert( shader->isSky ); - - sky_min = 1.0 / 256.0f; // FIXME: not correct? - sky_max = 255.0 / 256.0f; - - // set up for drawing - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - - if ( shader->sky.cloudHeight ) - { - for ( i = 0; i < MAX_SHADER_STAGES; i++ ) - { - if ( !tess.xstages[i] ) { - break; - } - FillCloudBox( shader, i ); - } - } -} - -/* -** R_InitSkyTexCoords -** Called when a sky shader is parsed -*/ -#define SQR( a ) ((a)*(a)) -void R_InitSkyTexCoords( float heightCloud ) -{ - int i, s, t; - float radiusWorld = 4096; - float p; - float sRad, tRad; - vec3_t skyVec; - vec3_t v; - - // init zfar so MakeSkyVec works even though - // a world hasn't been bounded - backEnd.viewParms.zFar = 1024; - - for ( i = 0; i < 6; i++ ) - { - for ( t = 0; t <= SKY_SUBDIVISIONS; t++ ) - { - for ( s = 0; s <= SKY_SUBDIVISIONS; s++ ) - { - // compute vector from view origin to sky side integral point - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - NULL, - skyVec ); - - // compute parametric value 'p' that intersects with cloud layer - p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) * - ( -2 * skyVec[2] * radiusWorld + - 2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) + - 2 * SQR( skyVec[0] ) * radiusWorld * heightCloud + - SQR( skyVec[0] ) * SQR( heightCloud ) + - 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud + - SQR( skyVec[1] ) * SQR( heightCloud ) + - 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud + - SQR( skyVec[2] ) * SQR( heightCloud ) ) ); - - s_cloudTexP[i][t][s] = p; - - // compute intersection point based on p - VectorScale( skyVec, p, v ); - v[2] += radiusWorld; - - // compute vector from world origin to intersection point 'v' - VectorNormalize( v ); - - sRad = Q_acos( v[0] ); - tRad = Q_acos( v[1] ); - - s_cloudTexCoords[i][t][s][0] = sRad; - s_cloudTexCoords[i][t][s][1] = tRad; - } - } - } -} - -//====================================================================================== - -/* -** RB_DrawSun -*/ -void RB_DrawSun( float scale, shader_t *shader ) { - float size; - float dist; - vec3_t origin, vec1, vec2; - - if ( !backEnd.skyRenderedThisView ) { - return; - } - - //qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); - //qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); - { - // FIXME: this could be a lot cleaner - mat4_t translation, modelview; - - Mat4Translation( backEnd.viewParms.or.origin, translation ); - Mat4Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview ); - GL_SetModelviewMatrix( modelview ); - } - - dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - size = dist * scale; - - VectorScale( tr.sunDirection, dist, origin ); - PerpendicularVector( vec1, tr.sunDirection ); - CrossProduct( tr.sunDirection, vec1, vec2 ); - - VectorScale( vec1, size, vec1 ); - VectorScale( vec2, size, vec2 ); - - // farthest depth range - qglDepthRange( 1.0, 1.0 ); - - RB_BeginSurface( shader, 0, 0 ); - - RB_AddQuadStamp(origin, vec1, vec2, colorWhite); - - RB_EndSurface(); - - // back to normal depth range - qglDepthRange( 0.0, 1.0 ); -} - - - - -/* -================ -RB_StageIteratorSky - -All of the visible sky triangles are in tess - -Other things could be stuck in here, like birds in the sky, etc -================ -*/ -void RB_StageIteratorSky( void ) { - if ( r_fastsky->integer ) { - return; - } - - // go through all the polygons and project them onto - // the sky box to see which blocks on each side need - // to be drawn - RB_ClipSkyPolygons( &tess ); - - // r_showsky will let all the sky blocks be drawn in - // front of everything to allow developers to see how - // much sky is getting sucked in - if ( r_showsky->integer ) { - qglDepthRange( 0.0, 0.0 ); - } else { - qglDepthRange( 1.0, 1.0 ); - } - - // draw the outer skybox - if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) { - mat4_t oldmodelview; - - GL_State( 0 ); - //qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); - - { - // FIXME: this could be a lot cleaner - mat4_t trans, product; - - Mat4Copy( glState.modelview, oldmodelview ); - Mat4Translation( backEnd.viewParms.or.origin, trans ); - Mat4Multiply( glState.modelview, trans, product ); - GL_SetModelviewMatrix( product ); - - } - - DrawSkyBox( tess.shader ); - - GL_SetModelviewMatrix( oldmodelview ); - } - - // generate the vertexes for all the clouds, which will be drawn - // by the generic shader routine - R_BuildCloudData( &tess ); - - RB_StageIteratorGeneric(); - - // draw the inner skybox - - - // back to normal depth range - qglDepthRange( 0.0, 1.0 ); - - // note that sky was drawn so we will draw a sun later - backEnd.skyRenderedThisView = qtrue; -} - - - - - diff --git a/code/renderergl2/tr_subs.c b/code/renderergl2/tr_subs.c deleted file mode 100644 index 6f4901287c..0000000000 --- a/code/renderergl2/tr_subs.c +++ /dev/null @@ -1,48 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_subs.c - common function replacements for modular renderer - -#include "tr_local.h" - -void QDECL Com_Printf( const char *msg, ... ) -{ - va_list argptr; - char text[1024]; - - va_start(argptr, msg); - Q_vsnprintf(text, sizeof(text), msg, argptr); - va_end(argptr); - - ri.Printf(PRINT_ALL, "%s", text); -} - -void QDECL Com_Error( int level, const char *error, ... ) -{ - va_list argptr; - char text[1024]; - - va_start(argptr, error); - Q_vsnprintf(text, sizeof(text), error, argptr); - va_end(argptr); - - ri.Error(level, "%s", text); -} diff --git a/code/renderergl2/tr_surface.c b/code/renderergl2/tr_surface.c deleted file mode 100644 index 825582bd21..0000000000 --- a/code/renderergl2/tr_surface.c +++ /dev/null @@ -1,1650 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_surf.c -#include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - -/* - - THIS ENTIRE FILE IS BACK END - -backEnd.currentEntity will be valid. - -Tess_Begin has already been called for the surface's shader. - -The modelview matrix will be set. - -It is safe to actually issue drawing commands here if you don't want to -use the shader system. -*/ - - -//============================================================================ - - -/* -============== -RB_CheckOverflow -============== -*/ -void RB_CheckOverflow( int verts, int indexes ) { - if (tess.numVertexes + verts < SHADER_MAX_VERTEXES - && tess.numIndexes + indexes < SHADER_MAX_INDEXES) { - return; - } - - RB_EndSurface(); - - if ( verts >= SHADER_MAX_VERTEXES ) { - ri.Error(ERR_DROP, "RB_CheckOverflow: verts > MAX (%d > %d)", verts, SHADER_MAX_VERTEXES ); - } - if ( indexes >= SHADER_MAX_INDEXES ) { - ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES ); - } - - RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex ); -} - -void RB_CheckVBOandIBO(VBO_t *vbo, IBO_t *ibo) -{ - if (!(vbo == glState.currentVBO && ibo == glState.currentIBO) || tess.multiDrawPrimitives >= MAX_MULTIDRAW_PRIMITIVES) - { - RB_EndSurface(); - RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); - - R_BindVBO(vbo); - R_BindIBO(ibo); - } - - if (vbo != tess.vbo && ibo != tess.ibo) - tess.useInternalVBO = qfalse; -} - - -/* -============== -RB_AddQuadStampExt -============== -*/ -void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], float s1, float t1, float s2, float t2 ) { - vec3_t normal; - int ndx; - - RB_CHECKOVERFLOW( 4, 6 ); - - ndx = tess.numVertexes; - - // triangle indexes for a simple quad - tess.indexes[ tess.numIndexes ] = ndx; - tess.indexes[ tess.numIndexes + 1 ] = ndx + 1; - tess.indexes[ tess.numIndexes + 2 ] = ndx + 3; - - tess.indexes[ tess.numIndexes + 3 ] = ndx + 3; - tess.indexes[ tess.numIndexes + 4 ] = ndx + 1; - tess.indexes[ tess.numIndexes + 5 ] = ndx + 2; - - tess.xyz[ndx][0] = origin[0] + left[0] + up[0]; - tess.xyz[ndx][1] = origin[1] + left[1] + up[1]; - tess.xyz[ndx][2] = origin[2] + left[2] + up[2]; - - tess.xyz[ndx+1][0] = origin[0] - left[0] + up[0]; - tess.xyz[ndx+1][1] = origin[1] - left[1] + up[1]; - tess.xyz[ndx+1][2] = origin[2] - left[2] + up[2]; - - tess.xyz[ndx+2][0] = origin[0] - left[0] - up[0]; - tess.xyz[ndx+2][1] = origin[1] - left[1] - up[1]; - tess.xyz[ndx+2][2] = origin[2] - left[2] - up[2]; - - tess.xyz[ndx+3][0] = origin[0] + left[0] - up[0]; - tess.xyz[ndx+3][1] = origin[1] + left[1] - up[1]; - tess.xyz[ndx+3][2] = origin[2] + left[2] - up[2]; - - - // constant normal all the way around - VectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal ); - - tess.normal[ndx] = - tess.normal[ndx+1] = - tess.normal[ndx+2] = - tess.normal[ndx+3] = R_VboPackNormal(normal); - - // standard square texture coordinates - VectorSet2(tess.texCoords[ndx ][0], s1, t1); - VectorSet2(tess.texCoords[ndx ][1], s1, t1); - - VectorSet2(tess.texCoords[ndx+1][0], s2, t1); - VectorSet2(tess.texCoords[ndx+1][1], s2, t1); - - VectorSet2(tess.texCoords[ndx+2][0], s2, t2); - VectorSet2(tess.texCoords[ndx+2][1], s2, t2); - - VectorSet2(tess.texCoords[ndx+3][0], s1, t2); - VectorSet2(tess.texCoords[ndx+3][1], s1, t2); - - // constant color all the way around - // should this be identity and let the shader specify from entity? - VectorCopy4(color, tess.vertexColors[ndx]); - VectorCopy4(color, tess.vertexColors[ndx+1]); - VectorCopy4(color, tess.vertexColors[ndx+2]); - VectorCopy4(color, tess.vertexColors[ndx+3]); - - tess.numVertexes += 4; - tess.numIndexes += 6; -} - -/* -============== -RB_AddQuadStamp -============== -*/ -void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, float color[4] ) { - RB_AddQuadStampExt( origin, left, up, color, 0, 0, 1, 1 ); -} - - -/* -============== -RB_InstantQuad - -based on Tess_InstantQuad from xreal -============== -*/ -void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4]) -{ - GLimp_LogComment("--- RB_InstantQuad2 ---\n"); - - tess.numVertexes = 0; - tess.numIndexes = 0; - tess.firstIndex = 0; - - VectorCopy4(quadVerts[0], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[0], tess.texCoords[tess.numVertexes][0]); - tess.numVertexes++; - - VectorCopy4(quadVerts[1], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[1], tess.texCoords[tess.numVertexes][0]); - tess.numVertexes++; - - VectorCopy4(quadVerts[2], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[2], tess.texCoords[tess.numVertexes][0]); - tess.numVertexes++; - - VectorCopy4(quadVerts[3], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[3], tess.texCoords[tess.numVertexes][0]); - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 1; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 3; - tess.minIndex = 0; - tess.maxIndex = 3; - - RB_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD); - - GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); - - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); - - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - tess.minIndex = 0; - tess.maxIndex = 0; -} - - -void RB_InstantQuad(vec4_t quadVerts[4]) -{ - vec2_t texCoords[4]; - - VectorSet2(texCoords[0], 0.0f, 0.0f); - VectorSet2(texCoords[1], 1.0f, 0.0f); - VectorSet2(texCoords[2], 1.0f, 1.0f); - VectorSet2(texCoords[3], 0.0f, 1.0f); - - GLSL_BindProgram(&tr.textureColorShader); - - GLSL_SetUniformMat4(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite); - - RB_InstantQuad2(quadVerts, texCoords); -} - - -/* -============== -RB_SurfaceSprite -============== -*/ -static void RB_SurfaceSprite( void ) { - vec3_t left, up; - float radius; - float colors[4]; - trRefEntity_t *ent = backEnd.currentEntity; - - // calculate the xyz locations for the four corners - radius = ent->e.radius; - if ( ent->e.rotation == 0 ) { - VectorScale( backEnd.viewParms.or.axis[1], radius, left ); - VectorScale( backEnd.viewParms.or.axis[2], radius, up ); - } else { - float s, c; - float ang; - - ang = M_PI * ent->e.rotation / 180; - s = sin( ang ); - c = cos( ang ); - - VectorScale( backEnd.viewParms.or.axis[1], c * radius, left ); - VectorMA( left, -s * radius, backEnd.viewParms.or.axis[2], left ); - - VectorScale( backEnd.viewParms.or.axis[2], c * radius, up ); - VectorMA( up, s * radius, backEnd.viewParms.or.axis[1], up ); - } - if ( backEnd.viewParms.isMirror ) { - VectorSubtract( vec3_origin, left, left ); - } - - VectorScale4(ent->e.shaderRGBA, 1.0f / 255.0f, colors); - - RB_AddQuadStamp( ent->e.origin, left, up, colors ); -} - - -/* -============= -RB_SurfacePolychain -============= -*/ -static void RB_SurfacePolychain( srfPoly_t *p ) { - int i; - int numv; - - RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) ); - - // fan triangles into the tess array - numv = tess.numVertexes; - for ( i = 0; i < p->numVerts; i++ ) { - VectorCopy( p->verts[i].xyz, tess.xyz[numv] ); - tess.texCoords[numv][0][0] = p->verts[i].st[0]; - tess.texCoords[numv][0][1] = p->verts[i].st[1]; - tess.vertexColors[numv][0] = p->verts[ i ].modulate[0] / 255.0f; - tess.vertexColors[numv][1] = p->verts[ i ].modulate[1] / 255.0f; - tess.vertexColors[numv][2] = p->verts[ i ].modulate[2] / 255.0f; - tess.vertexColors[numv][3] = p->verts[ i ].modulate[3] / 255.0f; - - numv++; - } - - // generate fan indexes into the tess array - for ( i = 0; i < p->numVerts-2; i++ ) { - tess.indexes[tess.numIndexes + 0] = tess.numVertexes; - tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1; - tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2; - tess.numIndexes += 3; - } - - tess.numVertexes = numv; -} - -static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIndexes, glIndex_t *indexes, int dlightBits, int pshadowBits) -{ - int i; - glIndex_t *inIndex; - srfVert_t *dv; - float *xyz, *texCoords, *lightCoords; - uint32_t *lightdir; - uint32_t *normal; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t *tangent; -#endif - glIndex_t *outIndex; - float *color; - - RB_CheckVBOandIBO(tess.vbo, tess.ibo); - - RB_CHECKOVERFLOW( numVerts, numIndexes ); - - inIndex = indexes; - outIndex = &tess.indexes[ tess.numIndexes ]; - for ( i = 0 ; i < numIndexes ; i++ ) { - *outIndex++ = tess.numVertexes + *inIndex++; - } - tess.numIndexes += numIndexes; - - if ( tess.shader->vertexAttribs & ATTR_POSITION ) - { - dv = verts; - xyz = tess.xyz[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, xyz+=4 ) - VectorCopy(dv->xyz, xyz); - } - - if ( tess.shader->vertexAttribs & ATTR_NORMAL ) - { - dv = verts; - normal = &tess.normal[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, normal++ ) - *normal = R_VboPackNormal(dv->normal); - } - -#ifdef USE_VERT_TANGENT_SPACE - if ( tess.shader->vertexAttribs & ATTR_TANGENT ) - { - dv = verts; - tangent = &tess.tangent[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, tangent++ ) - *tangent = R_VboPackTangent(dv->tangent); - } -#endif - - if ( tess.shader->vertexAttribs & ATTR_TEXCOORD ) - { - dv = verts; - texCoords = tess.texCoords[ tess.numVertexes ][0]; - for ( i = 0 ; i < numVerts ; i++, dv++, texCoords+=4 ) - VectorCopy2(dv->st, texCoords); - } - - if ( tess.shader->vertexAttribs & ATTR_LIGHTCOORD ) - { - dv = verts; - lightCoords = tess.texCoords[ tess.numVertexes ][1]; - for ( i = 0 ; i < numVerts ; i++, dv++, lightCoords+=4 ) - VectorCopy2(dv->lightmap, lightCoords); - } - - if ( tess.shader->vertexAttribs & ATTR_COLOR ) - { - dv = verts; - color = tess.vertexColors[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, color+=4 ) - VectorCopy4(dv->vertexColors, color); - } - - if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION ) - { - dv = verts; - lightdir = &tess.lightdir[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, lightdir++ ) - *lightdir = R_VboPackNormal(dv->lightdir); - } - -#if 0 // nothing even uses vertex dlightbits - for ( i = 0 ; i < numVerts ; i++ ) { - tess.vertexDlightBits[ tess.numVertexes + i ] = dlightBits; - } -#endif - - tess.dlightBits |= dlightBits; - tess.pshadowBits |= pshadowBits; - - tess.numVertexes += numVerts; -} - -static qboolean RB_SurfaceVbo(VBO_t *vbo, IBO_t *ibo, int numVerts, int numIndexes, int firstIndex, int minIndex, int maxIndex, int dlightBits, int pshadowBits, qboolean shaderCheck) -{ - int i, mergeForward, mergeBack; - GLvoid *firstIndexOffset, *lastIndexOffset; - - if (!vbo || !ibo) - { - return qfalse; - } - - if (shaderCheck && !(!ShaderRequiresCPUDeforms(tess.shader) && !tess.shader->isSky && !tess.shader->isPortal)) - { - return qfalse; - } - - RB_CheckVBOandIBO(vbo, ibo); - - tess.dlightBits |= dlightBits; - tess.pshadowBits |= pshadowBits; - - // merge this into any existing multidraw primitives - mergeForward = -1; - mergeBack = -1; - firstIndexOffset = BUFFER_OFFSET(firstIndex * sizeof(glIndex_t)); - lastIndexOffset = BUFFER_OFFSET((firstIndex + numIndexes) * sizeof(glIndex_t)); - - if (r_mergeMultidraws->integer) - { - i = 0; - - if (r_mergeMultidraws->integer == 1) - { - // lazy merge, only check the last primitive - if (tess.multiDrawPrimitives) - { - i = tess.multiDrawPrimitives - 1; - } - } - - for (; i < tess.multiDrawPrimitives; i++) - { - if (tess.multiDrawLastIndex[i] == firstIndexOffset) - { - mergeBack = i; - } - - if (lastIndexOffset == tess.multiDrawFirstIndex[i]) - { - mergeForward = i; - } - } - } - - if (mergeBack != -1 && mergeForward == -1) - { - tess.multiDrawNumIndexes[mergeBack] += numIndexes; - tess.multiDrawLastIndex[mergeBack] = tess.multiDrawFirstIndex[mergeBack] + tess.multiDrawNumIndexes[mergeBack]; - tess.multiDrawMinIndex[mergeBack] = MIN(tess.multiDrawMinIndex[mergeBack], minIndex); - tess.multiDrawMaxIndex[mergeBack] = MAX(tess.multiDrawMaxIndex[mergeBack], maxIndex); - backEnd.pc.c_multidrawsMerged++; - } - else if (mergeBack == -1 && mergeForward != -1) - { - tess.multiDrawNumIndexes[mergeForward] += numIndexes; - tess.multiDrawFirstIndex[mergeForward] = firstIndexOffset; - tess.multiDrawLastIndex[mergeForward] = tess.multiDrawFirstIndex[mergeForward] + tess.multiDrawNumIndexes[mergeForward]; - tess.multiDrawMinIndex[mergeForward] = MIN(tess.multiDrawMinIndex[mergeForward], minIndex); - tess.multiDrawMaxIndex[mergeForward] = MAX(tess.multiDrawMaxIndex[mergeForward], maxIndex); - backEnd.pc.c_multidrawsMerged++; - } - else if (mergeBack != -1 && mergeForward != -1) - { - tess.multiDrawNumIndexes[mergeBack] += numIndexes + tess.multiDrawNumIndexes[mergeForward]; - tess.multiDrawLastIndex[mergeBack] = tess.multiDrawFirstIndex[mergeBack] + tess.multiDrawNumIndexes[mergeBack]; - tess.multiDrawMinIndex[mergeBack] = MIN(tess.multiDrawMinIndex[mergeBack], MIN(tess.multiDrawMinIndex[mergeForward], minIndex)); - tess.multiDrawMaxIndex[mergeBack] = MAX(tess.multiDrawMaxIndex[mergeBack], MAX(tess.multiDrawMaxIndex[mergeForward], maxIndex)); - tess.multiDrawPrimitives--; - - if (mergeForward != tess.multiDrawPrimitives) - { - tess.multiDrawNumIndexes[mergeForward] = tess.multiDrawNumIndexes[tess.multiDrawPrimitives]; - tess.multiDrawFirstIndex[mergeForward] = tess.multiDrawFirstIndex[tess.multiDrawPrimitives]; - } - backEnd.pc.c_multidrawsMerged += 2; - } - else if (mergeBack == -1 && mergeForward == -1) - { - tess.multiDrawNumIndexes[tess.multiDrawPrimitives] = numIndexes; - tess.multiDrawFirstIndex[tess.multiDrawPrimitives] = firstIndexOffset; - tess.multiDrawLastIndex[tess.multiDrawPrimitives] = lastIndexOffset; - tess.multiDrawMinIndex[tess.multiDrawPrimitives] = minIndex; - tess.multiDrawMaxIndex[tess.multiDrawPrimitives] = maxIndex; - tess.multiDrawPrimitives++; - } - - backEnd.pc.c_multidraws++; - - tess.numIndexes += numIndexes; - tess.numVertexes += numVerts; - - return qtrue; -} - -/* -============= -RB_SurfaceTriangles -============= -*/ -static void RB_SurfaceTriangles( srfBspSurface_t *srf ) { - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, - srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) - { - return; - } - - RB_SurfaceVertsAndIndexes(srf->numVerts, srf->verts, srf->numIndexes, - srf->indexes, srf->dlightBits, srf->pshadowBits); -} - - - -/* -============== -RB_SurfaceBeam -============== -*/ -static void RB_SurfaceBeam( void ) -{ -#define NUM_BEAM_SEGS 6 - refEntity_t *e; - shaderProgram_t *sp = &tr.textureColorShader; - int i; - vec3_t perpvec; - vec3_t direction, normalized_direction; - vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS]; - vec3_t oldorigin, origin; - - e = &backEnd.currentEntity->e; - - oldorigin[0] = e->oldorigin[0]; - oldorigin[1] = e->oldorigin[1]; - oldorigin[2] = e->oldorigin[2]; - - origin[0] = e->origin[0]; - origin[1] = e->origin[1]; - origin[2] = e->origin[2]; - - normalized_direction[0] = direction[0] = oldorigin[0] - origin[0]; - normalized_direction[1] = direction[1] = oldorigin[1] - origin[1]; - normalized_direction[2] = direction[2] = oldorigin[2] - origin[2]; - - if ( VectorNormalize( normalized_direction ) == 0 ) - return; - - PerpendicularVector( perpvec, normalized_direction ); - - VectorScale( perpvec, 4, perpvec ); - - for ( i = 0; i < NUM_BEAM_SEGS ; i++ ) - { - RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i ); -// VectorAdd( start_points[i], origin, start_points[i] ); - VectorAdd( start_points[i], direction, end_points[i] ); - } - - GL_Bind( tr.whiteImage ); - - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - // FIXME: Quake3 doesn't use this, so I never tested it - tess.numVertexes = 0; - tess.numIndexes = 0; - tess.firstIndex = 0; - tess.minIndex = 0; - tess.maxIndex = 0; - - for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) { - VectorCopy(start_points[ i % NUM_BEAM_SEGS ], tess.xyz[tess.numVertexes++]); - VectorCopy(end_points [ i % NUM_BEAM_SEGS ], tess.xyz[tess.numVertexes++]); - } - - for ( i = 0; i < NUM_BEAM_SEGS; i++ ) { - tess.indexes[tess.numIndexes++] = i * 2; - tess.indexes[tess.numIndexes++] = (i + 1) * 2; - tess.indexes[tess.numIndexes++] = 1 + i * 2; - - tess.indexes[tess.numIndexes++] = 1 + i * 2; - tess.indexes[tess.numIndexes++] = (i + 1) * 2; - tess.indexes[tess.numIndexes++] = 1 + (i + 1) * 2; - } - - tess.minIndex = 0; - tess.maxIndex = tess.numVertexes; - - // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function - RB_UpdateVBOs(ATTR_POSITION); - - GLSL_VertexAttribsState(ATTR_POSITION); - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - GLSL_SetUniformVec4(sp, UNIFORM_COLOR, colorRed); - - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); - - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - tess.minIndex = 0; - tess.maxIndex = 0; -} - -//================================================================================ - -static void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, float len, float spanWidth ) -{ - float spanWidth2; - int vbase; - float t = len / 256.0f; - - RB_CHECKOVERFLOW( 4, 6 ); - - vbase = tess.numVertexes; - - spanWidth2 = -spanWidth; - - // FIXME: use quad stamp? - VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25 / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25 / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25 / 255.0f; - tess.numVertexes++; - - VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; - tess.numVertexes++; - - VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] ); - - tess.texCoords[tess.numVertexes][0][0] = t; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; - tess.numVertexes++; - - VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = t; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = vbase; - tess.indexes[tess.numIndexes++] = vbase + 1; - tess.indexes[tess.numIndexes++] = vbase + 2; - - tess.indexes[tess.numIndexes++] = vbase + 2; - tess.indexes[tess.numIndexes++] = vbase + 1; - tess.indexes[tess.numIndexes++] = vbase + 3; -} - -static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, const vec3_t right, const vec3_t up ) -{ - int i; - vec3_t pos[4]; - vec3_t v; - int spanWidth = r_railWidth->integer; - float c, s; - float scale; - - if ( numSegs > 1 ) - numSegs--; - if ( !numSegs ) - return; - - scale = 0.25; - - for ( i = 0; i < 4; i++ ) - { - c = cos( DEG2RAD( 45 + i * 90 ) ); - s = sin( DEG2RAD( 45 + i * 90 ) ); - v[0] = ( right[0] * c + up[0] * s ) * scale * spanWidth; - v[1] = ( right[1] * c + up[1] * s ) * scale * spanWidth; - v[2] = ( right[2] * c + up[2] * s ) * scale * spanWidth; - VectorAdd( start, v, pos[i] ); - - if ( numSegs > 1 ) - { - // offset by 1 segment if we're doing a long distance shot - VectorAdd( pos[i], dir, pos[i] ); - } - } - - for ( i = 0; i < numSegs; i++ ) - { - int j; - - RB_CHECKOVERFLOW( 4, 6 ); - - for ( j = 0; j < 4; j++ ) - { - VectorCopy( pos[j], tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = ( j < 2 ); - tess.texCoords[tess.numVertexes][0][1] = ( j && j != 3 ); - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; - tess.numVertexes++; - - VectorAdd( pos[j], dir, pos[j] ); - } - - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 0; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 2; - } -} - -/* -** RB_SurfaceRailRinges -*/ -static void RB_SurfaceRailRings( void ) { - refEntity_t *e; - int numSegs; - int len; - vec3_t vec; - vec3_t right, up; - vec3_t start, end; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, start ); - VectorCopy( e->origin, end ); - - // compute variables - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - MakeNormalVectors( vec, right, up ); - numSegs = ( len ) / r_railSegmentLength->value; - if ( numSegs <= 0 ) { - numSegs = 1; - } - - VectorScale( vec, r_railSegmentLength->value, vec ); - - DoRailDiscs( numSegs, start, vec, right, up ); -} - -/* -** RB_SurfaceRailCore -*/ -static void RB_SurfaceRailCore( void ) { - refEntity_t *e; - int len; - vec3_t right; - vec3_t vec; - vec3_t start, end; - vec3_t v1, v2; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, start ); - VectorCopy( e->origin, end ); - - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - - // compute side vector - VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); - VectorNormalize( v1 ); - VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); - VectorNormalize( v2 ); - CrossProduct( v1, v2, right ); - VectorNormalize( right ); - - DoRailCore( start, end, right, len, r_railCoreWidth->integer ); -} - -/* -** RB_SurfaceLightningBolt -*/ -static void RB_SurfaceLightningBolt( void ) { - refEntity_t *e; - int len; - vec3_t right; - vec3_t vec; - vec3_t start, end; - vec3_t v1, v2; - int i; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, end ); - VectorCopy( e->origin, start ); - - // compute variables - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - - // compute side vector - VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); - VectorNormalize( v1 ); - VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); - VectorNormalize( v2 ); - CrossProduct( v1, v2, right ); - VectorNormalize( right ); - - for ( i = 0 ; i < 4 ; i++ ) { - vec3_t temp; - - DoRailCore( start, end, right, len, 8 ); - RotatePointAroundVector( temp, vec, right, 45 ); - VectorCopy( temp, right ); - } -} - -#if 0 -/* -** VectorArrayNormalize -* -* The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0) -* This means that we don't have to worry about zero length or enormously long vectors. -*/ -static void VectorArrayNormalize(vec4_t *normals, unsigned int count) -{ -// assert(count); - -#if idppc - { - register float half = 0.5; - register float one = 1.0; - float *components = (float *)normals; - - // Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction, - // runs *much* faster than calling sqrt(). We'll use a single Newton-Raphson - // refinement step to get a little more precision. This seems to yeild results - // that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5). - // (That is, for the given input range of about 0.6 to 2.0). - do { - float x, y, z; - float B, y0, y1; - - x = components[0]; - y = components[1]; - z = components[2]; - components += 4; - B = x*x + y*y + z*z; - -#ifdef __GNUC__ - asm("frsqrte %0,%1" : "=f" (y0) : "f" (B)); -#else - y0 = __frsqrte(B); -#endif - y1 = y0 + half*y0*(one - B*y0*y0); - - x = x * y1; - y = y * y1; - components[-4] = x; - z = z * y1; - components[-3] = y; - components[-2] = z; - } while(count--); - } -#else // No assembly version for this architecture, or C_ONLY defined - // given the input, it's safe to call VectorNormalizeFast - while (count--) { - VectorNormalizeFast(normals[0]); - normals++; - } -#endif - -} -#endif - - - -/* -** LerpMeshVertexes -*/ -#if 0 -#if idppc_altivec -static void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp) -{ - short *oldXyz, *newXyz, *oldNormals, *newNormals; - float *outXyz, *outNormal; - float oldXyzScale QALIGN(16); - float newXyzScale QALIGN(16); - float oldNormalScale QALIGN(16); - float newNormalScale QALIGN(16); - int vertNum; - unsigned lat, lng; - int numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; - - newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.frame * surf->numVerts * 4); - newNormals = newXyz + 3; - - newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); - newNormalScale = 1.0 - backlerp; - - numVerts = surf->numVerts; - - if ( backlerp == 0 ) { - vector signed short newNormalsVec0; - vector signed short newNormalsVec1; - vector signed int newNormalsIntVec; - vector float newNormalsFloatVec; - vector float newXyzScaleVec; - vector unsigned char newNormalsLoadPermute; - vector unsigned char newNormalsStorePermute; - vector float zero; - - newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec); - newXyzScaleVec = *(vector float *)&newXyzScale; - newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute); - newXyzScaleVec = vec_splat(newXyzScaleVec,0); - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - zero = (vector float)vec_splat_s8(0); - // - // just copy the vertexes - // - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - newXyz += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - newNormalsVec0 = vec_ld(0,newXyz); - newNormalsVec1 = vec_ld(16,newXyz); - newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute); - newNormalsIntVec = vec_unpackh(newNormalsVec0); - newNormalsFloatVec = vec_ctf(newNormalsIntVec,0); - newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero); - newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute); - //outXyz[0] = newXyz[0] * newXyzScale; - //outXyz[1] = newXyz[1] * newXyzScale; - //outXyz[2] = newXyz[2] * newXyzScale; - - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - vec_ste(newNormalsFloatVec,0,outXyz); - vec_ste(newNormalsFloatVec,4,outXyz); - vec_ste(newNormalsFloatVec,8,outXyz); - } - } else { - // - // interpolate and copy the vertex and normal - // - oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); - oldNormals = oldXyz + 3; - - oldXyzScale = MD3_XYZ_SCALE * backlerp; - oldNormalScale = backlerp; - - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - vec3_t uncompressedOldNormal, uncompressedNewNormal; - - // interpolate the xyz - outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; - outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; - outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; - - // FIXME: interpolate lat/long instead? - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - lat = ( oldNormals[0] >> 8 ) & 0xff; - lng = ( oldNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - - uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; - outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; - outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; - -// VectorNormalize (outNormal); - } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); - } -} -#endif -#endif - -static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp) -{ -#if 0 - short *oldXyz, *newXyz, *oldNormals, *newNormals; - float *outXyz, *outNormal; - float oldXyzScale, newXyzScale; - float oldNormalScale, newNormalScale; - int vertNum; - unsigned lat, lng; - int numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; - - newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.frame * surf->numVerts * 4); - newNormals = newXyz + 3; - - newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); - newNormalScale = 1.0 - backlerp; - - numVerts = surf->numVerts; - - if ( backlerp == 0 ) { - // - // just copy the vertexes - // - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - newXyz += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - - outXyz[0] = newXyz[0] * newXyzScale; - outXyz[1] = newXyz[1] * newXyzScale; - outXyz[2] = newXyz[2] * newXyzScale; - - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - } - } else { - // - // interpolate and copy the vertex and normal - // - oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); - oldNormals = oldXyz + 3; - - oldXyzScale = MD3_XYZ_SCALE * backlerp; - oldNormalScale = backlerp; - - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - vec3_t uncompressedOldNormal, uncompressedNewNormal; - - // interpolate the xyz - outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; - outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; - outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; - - // FIXME: interpolate lat/long instead? - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - lat = ( oldNormals[0] >> 8 ) & 0xff; - lng = ( oldNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - - uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; - outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; - outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; - -// VectorNormalize (outNormal); - } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); - } -#endif - float *outXyz; - uint32_t *outNormal; - mdvVertex_t *newVerts; - int vertNum; - - newVerts = surf->verts + backEnd.currentEntity->e.frame * surf->numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = &tess.normal[tess.numVertexes]; - - if (backlerp == 0) - { - // - // just copy the vertexes - // - - for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++) - { - vec3_t normal; - - VectorCopy(newVerts->xyz, outXyz); - VectorCopy(newVerts->normal, normal); - - *outNormal = R_VboPackNormal(normal); - - newVerts++; - outXyz += 4; - outNormal++; - } - } - else - { - // - // interpolate and copy the vertex and normal - // - - mdvVertex_t *oldVerts; - - oldVerts = surf->verts + backEnd.currentEntity->e.oldframe * surf->numVerts; - - for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++) - { - vec3_t normal; - - VectorLerp(newVerts->xyz, oldVerts->xyz, backlerp, outXyz); - VectorLerp(newVerts->normal, oldVerts->normal, backlerp, normal); - VectorNormalize(normal); - - *outNormal = R_VboPackNormal(normal); - - newVerts++; - oldVerts++; - outXyz += 4; - outNormal++; - } - } - -} - -static void LerpMeshVertexes(mdvSurface_t *surf, float backlerp) -{ -#if 0 -#if idppc_altivec - if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. - LerpMeshVertexes_altivec( surf, backlerp ); - return; - } -#endif // idppc_altivec -#endif - LerpMeshVertexes_scalar( surf, backlerp ); -} - - -/* -============= -RB_SurfaceMesh -============= -*/ -static void RB_SurfaceMesh(mdvSurface_t *surface) { - int j; - float backlerp; - mdvSt_t *texCoords; - int Bob, Doug; - int numVerts; - - if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) { - backlerp = 0; - } else { - backlerp = backEnd.currentEntity->e.backlerp; - } - - RB_CHECKOVERFLOW( surface->numVerts, surface->numIndexes ); - - LerpMeshVertexes (surface, backlerp); - - Bob = tess.numIndexes; - Doug = tess.numVertexes; - for (j = 0 ; j < surface->numIndexes ; j++) { - tess.indexes[Bob + j] = Doug + surface->indexes[j]; - } - tess.numIndexes += surface->numIndexes; - - texCoords = surface->st; - - numVerts = surface->numVerts; - for ( j = 0; j < numVerts; j++ ) { - tess.texCoords[Doug + j][0][0] = texCoords[j].st[0]; - tess.texCoords[Doug + j][0][1] = texCoords[j].st[1]; - // FIXME: fill in lightmapST for completeness? - } - - tess.numVertexes += surface->numVerts; - -} - - -/* -============== -RB_SurfaceFace -============== -*/ -static void RB_SurfaceFace( srfBspSurface_t *srf ) { - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, - srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) - { - return; - } - - RB_SurfaceVertsAndIndexes(srf->numVerts, srf->verts, srf->numIndexes, - srf->indexes, srf->dlightBits, srf->pshadowBits); -} - - -static float LodErrorForVolume( vec3_t local, float radius ) { - vec3_t world; - float d; - - // never let it go negative - if ( r_lodCurveError->value < 0 ) { - return 0; - } - - world[0] = local[0] * backEnd.or.axis[0][0] + local[1] * backEnd.or.axis[1][0] + - local[2] * backEnd.or.axis[2][0] + backEnd.or.origin[0]; - world[1] = local[0] * backEnd.or.axis[0][1] + local[1] * backEnd.or.axis[1][1] + - local[2] * backEnd.or.axis[2][1] + backEnd.or.origin[1]; - world[2] = local[0] * backEnd.or.axis[0][2] + local[1] * backEnd.or.axis[1][2] + - local[2] * backEnd.or.axis[2][2] + backEnd.or.origin[2]; - - VectorSubtract( world, backEnd.viewParms.or.origin, world ); - d = DotProduct( world, backEnd.viewParms.or.axis[0] ); - - if ( d < 0 ) { - d = -d; - } - d -= radius; - if ( d < 1 ) { - d = 1; - } - - return r_lodCurveError->value / d; -} - -/* -============= -RB_SurfaceGrid - -Just copy the grid of points and triangulate -============= -*/ -static void RB_SurfaceGrid( srfBspSurface_t *srf ) { - int i, j; - float *xyz; - float *texCoords, *lightCoords; - uint32_t *normal; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t *tangent; -#endif - float *color; - uint32_t *lightdir; - srfVert_t *dv; - int rows, irows, vrows; - int used; - int widthTable[MAX_GRID_SIZE]; - int heightTable[MAX_GRID_SIZE]; - float lodError; - int lodWidth, lodHeight; - int numVertexes; - int dlightBits; - int pshadowBits; - //int *vDlightBits; - - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, - srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) - { - return; - } - - dlightBits = srf->dlightBits; - tess.dlightBits |= dlightBits; - - pshadowBits = srf->pshadowBits; - tess.pshadowBits |= pshadowBits; - - // determine the allowable discrepance - lodError = LodErrorForVolume( srf->lodOrigin, srf->lodRadius ); - - // determine which rows and columns of the subdivision - // we are actually going to use - widthTable[0] = 0; - lodWidth = 1; - for ( i = 1 ; i < srf->width-1 ; i++ ) { - if ( srf->widthLodError[i] <= lodError ) { - widthTable[lodWidth] = i; - lodWidth++; - } - } - widthTable[lodWidth] = srf->width-1; - lodWidth++; - - heightTable[0] = 0; - lodHeight = 1; - for ( i = 1 ; i < srf->height-1 ; i++ ) { - if ( srf->heightLodError[i] <= lodError ) { - heightTable[lodHeight] = i; - lodHeight++; - } - } - heightTable[lodHeight] = srf->height-1; - lodHeight++; - - - // very large grids may have more points or indexes than can be fit - // in the tess structure, so we may have to issue it in multiple passes - - used = 0; - while ( used < lodHeight - 1 ) { - // see how many rows of both verts and indexes we can add without overflowing - do { - vrows = ( SHADER_MAX_VERTEXES - tess.numVertexes ) / lodWidth; - irows = ( SHADER_MAX_INDEXES - tess.numIndexes ) / ( lodWidth * 6 ); - - // if we don't have enough space for at least one strip, flush the buffer - if ( vrows < 2 || irows < 1 ) { - RB_EndSurface(); - RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex ); - } else { - break; - } - } while ( 1 ); - - rows = irows; - if ( vrows < irows + 1 ) { - rows = vrows - 1; - } - if ( used + rows > lodHeight ) { - rows = lodHeight - used; - } - - numVertexes = tess.numVertexes; - - xyz = tess.xyz[numVertexes]; - normal = &tess.normal[numVertexes]; -#ifdef USE_VERT_TANGENT_SPACE - tangent = &tess.tangent[numVertexes]; -#endif - texCoords = tess.texCoords[numVertexes][0]; - lightCoords = tess.texCoords[numVertexes][1]; - color = tess.vertexColors[numVertexes]; - lightdir = &tess.lightdir[numVertexes]; - //vDlightBits = &tess.vertexDlightBits[numVertexes]; - - for ( i = 0 ; i < rows ; i++ ) { - for ( j = 0 ; j < lodWidth ; j++ ) { - dv = srf->verts + heightTable[ used + i ] * srf->width - + widthTable[ j ]; - - if ( tess.shader->vertexAttribs & ATTR_POSITION ) - { - VectorCopy(dv->xyz, xyz); - xyz += 4; - } - - if ( tess.shader->vertexAttribs & ATTR_NORMAL ) - { - *normal++ = R_VboPackNormal(dv->normal); - } - -#ifdef USE_VERT_TANGENT_SPACE - if ( tess.shader->vertexAttribs & ATTR_TANGENT ) - { - *tangent++ = R_VboPackTangent(dv->tangent); - } -#endif - if ( tess.shader->vertexAttribs & ATTR_TEXCOORD ) - { - VectorCopy2(dv->st, texCoords); - texCoords += 4; - } - - if ( tess.shader->vertexAttribs & ATTR_LIGHTCOORD ) - { - VectorCopy2(dv->lightmap, lightCoords); - lightCoords += 4; - } - - if ( tess.shader->vertexAttribs & ATTR_COLOR ) - { - VectorCopy4(dv->vertexColors, color); - color += 4; - } - - if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION ) - { - *lightdir++ = R_VboPackNormal(dv->lightdir); - } - - //*vDlightBits++ = dlightBits; - } - } - - - // add the indexes - { - int numIndexes; - int w, h; - - h = rows - 1; - w = lodWidth - 1; - numIndexes = tess.numIndexes; - for (i = 0 ; i < h ; i++) { - for (j = 0 ; j < w ; j++) { - int v1, v2, v3, v4; - - // vertex order to be reckognized as tristrips - v1 = numVertexes + i*lodWidth + j + 1; - v2 = v1 - 1; - v3 = v2 + lodWidth; - v4 = v3 + 1; - - tess.indexes[numIndexes] = v2; - tess.indexes[numIndexes+1] = v3; - tess.indexes[numIndexes+2] = v1; - - tess.indexes[numIndexes+3] = v1; - tess.indexes[numIndexes+4] = v3; - tess.indexes[numIndexes+5] = v4; - numIndexes += 6; - } - } - - tess.numIndexes = numIndexes; - } - - tess.numVertexes += rows * lodWidth; - - used += rows - 1; - } -} - - -/* -=========================================================================== - -NULL MODEL - -=========================================================================== -*/ - -/* -=================== -RB_SurfaceAxis - -Draws x/y/z lines from the origin for orientation debugging -=================== -*/ -static void RB_SurfaceAxis( void ) { - // FIXME: implement this -#if 0 - GL_Bind( tr.whiteImage ); - GL_State( GLS_DEFAULT ); - qglLineWidth( 3 ); - qglBegin( GL_LINES ); - qglColor3f( 1,0,0 ); - qglVertex3f( 0,0,0 ); - qglVertex3f( 16,0,0 ); - qglColor3f( 0,1,0 ); - qglVertex3f( 0,0,0 ); - qglVertex3f( 0,16,0 ); - qglColor3f( 0,0,1 ); - qglVertex3f( 0,0,0 ); - qglVertex3f( 0,0,16 ); - qglEnd(); - qglLineWidth( 1 ); -#endif -} - -//=========================================================================== - -/* -==================== -RB_SurfaceEntity - -Entities that have a single procedurally generated surface -==================== -*/ -static void RB_SurfaceEntity( surfaceType_t *surfType ) { - switch( backEnd.currentEntity->e.reType ) { - case RT_SPRITE: - RB_SurfaceSprite(); - break; - case RT_BEAM: - RB_SurfaceBeam(); - break; - case RT_RAIL_CORE: - RB_SurfaceRailCore(); - break; - case RT_RAIL_RINGS: - RB_SurfaceRailRings(); - break; - case RT_LIGHTNING: - RB_SurfaceLightningBolt(); - break; - default: - RB_SurfaceAxis(); - break; - } -} - -static void RB_SurfaceBad( surfaceType_t *surfType ) { - ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" ); -} - -static void RB_SurfaceFlare(srfFlare_t *surf) -{ - if (r_flares->integer) - RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal); -} - -static void RB_SurfaceVBOMesh(srfBspSurface_t * srf) -{ - RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, srf->firstIndex, - srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qfalse ); -} - -void RB_SurfaceVBOMDVMesh(srfVBOMDVMesh_t * surface) -{ - //mdvModel_t *mdvModel; - //mdvSurface_t *mdvSurface; - refEntity_t *refEnt; - - GLimp_LogComment("--- RB_SurfaceVBOMDVMesh ---\n"); - - if(!surface->vbo || !surface->ibo) - return; - - //RB_CheckVBOandIBO(surface->vbo, surface->ibo); - RB_EndSurface(); - RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); - - R_BindVBO(surface->vbo); - R_BindIBO(surface->ibo); - - tess.useInternalVBO = qfalse; - - tess.numIndexes += surface->numIndexes; - tess.numVertexes += surface->numVerts; - tess.minIndex = surface->minIndex; - tess.maxIndex = surface->maxIndex; - - //mdvModel = surface->mdvModel; - //mdvSurface = surface->mdvSurface; - - refEnt = &backEnd.currentEntity->e; - - if(refEnt->oldframe == refEnt->frame) - { - glState.vertexAttribsInterpolation = 0; - } - else - { - glState.vertexAttribsInterpolation = refEnt->backlerp; - } - - glState.vertexAttribsOldFrame = refEnt->oldframe; - glState.vertexAttribsNewFrame = refEnt->frame; - glState.vertexAnimation = qtrue; - - RB_EndSurface(); - - // So we don't lerp surfaces that shouldn't be lerped - glState.vertexAnimation = qfalse; -} - -static void RB_SurfaceDisplayList( srfDisplayList_t *surf ) { - // all apropriate state must be set in RB_BeginSurface - // this isn't implemented yet... - qglCallList( surf->listNum ); -} - -static void RB_SurfaceSkip( void *surf ) { -} - - -void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { - (void(*)(void*))RB_SurfaceBad, // SF_BAD, - (void(*)(void*))RB_SurfaceSkip, // SF_SKIP, - (void(*)(void*))RB_SurfaceFace, // SF_FACE, - (void(*)(void*))RB_SurfaceGrid, // SF_GRID, - (void(*)(void*))RB_SurfaceTriangles, // SF_TRIANGLES, - (void(*)(void*))RB_SurfacePolychain, // SF_POLY, - (void(*)(void*))RB_SurfaceMesh, // SF_MDV, - (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR, - (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, - (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, - (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY - (void(*)(void*))RB_SurfaceDisplayList, // SF_DISPLAY_LIST - (void(*)(void*))RB_SurfaceVBOMesh, // SF_VBO_MESH, - (void(*)(void*))RB_SurfaceVBOMDVMesh, // SF_VBO_MDVMESH -}; diff --git a/code/renderergl2/tr_vbo.c b/code/renderergl2/tr_vbo.c deleted file mode 100644 index dc0f33beb3..0000000000 --- a/code/renderergl2/tr_vbo.c +++ /dev/null @@ -1,971 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2007-2009 Robert Beckebans - -This file is part of XreaL source code. - -XreaL source code 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. - -XreaL source code 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 XreaL source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_vbo.c -#include "tr_local.h" - - -uint32_t R_VboPackTangent(vec4_t v) -{ - if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) - { - return (((uint32_t)(v[3] * 1.5f + 2.0f )) << 30) - | (((uint32_t)(v[2] * 511.5f + 512.0f)) << 20) - | (((uint32_t)(v[1] * 511.5f + 512.0f)) << 10) - | (((uint32_t)(v[0] * 511.5f + 512.0f))); - } - else - { - return (((uint32_t)(v[3] * 127.5f + 128.0f)) << 24) - | (((uint32_t)(v[2] * 127.5f + 128.0f)) << 16) - | (((uint32_t)(v[1] * 127.5f + 128.0f)) << 8) - | (((uint32_t)(v[0] * 127.5f + 128.0f))); - } -} - -uint32_t R_VboPackNormal(vec3_t v) -{ - if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) - { - return (((uint32_t)(v[2] * 511.5f + 512.0f)) << 20) - | (((uint32_t)(v[1] * 511.5f + 512.0f)) << 10) - | (((uint32_t)(v[0] * 511.5f + 512.0f))); - } - else - { - return (((uint32_t)(v[2] * 127.5f + 128.0f)) << 16) - | (((uint32_t)(v[1] * 127.5f + 128.0f)) << 8) - | (((uint32_t)(v[0] * 127.5f + 128.0f))); - } -} - -void R_VboUnpackTangent(vec4_t v, uint32_t b) -{ - if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) - { - v[0] = ((b) & 0x3ff) * 1.0f/511.5f - 1.0f; - v[1] = ((b >> 10) & 0x3ff) * 1.0f/511.5f - 1.0f; - v[2] = ((b >> 20) & 0x3ff) * 1.0f/511.5f - 1.0f; - v[3] = ((b >> 30) & 0x3) * 1.0f/1.5f - 1.0f; - } - else - { - v[0] = ((b) & 0xff) * 1.0f/127.5f - 1.0f; - v[1] = ((b >> 8) & 0xff) * 1.0f/127.5f - 1.0f; - v[2] = ((b >> 16) & 0xff) * 1.0f/127.5f - 1.0f; - v[3] = ((b >> 24) & 0xff) * 1.0f/127.5f - 1.0f; - } -} - -void R_VboUnpackNormal(vec3_t v, uint32_t b) -{ - if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) - { - v[0] = ((b) & 0x3ff) * 1.0f/511.5f - 1.0f; - v[1] = ((b >> 10) & 0x3ff) * 1.0f/511.5f - 1.0f; - v[2] = ((b >> 20) & 0x3ff) * 1.0f/511.5f - 1.0f; - } - else - { - v[0] = ((b) & 0xff) * 1.0f/127.5f - 1.0f; - v[1] = ((b >> 8) & 0xff) * 1.0f/127.5f - 1.0f; - v[2] = ((b >> 16) & 0xff) * 1.0f/127.5f - 1.0f; - } -} - -/* -============ -R_CreateVBO -============ -*/ -VBO_t *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, vboUsage_t usage) -{ - VBO_t *vbo; - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateVBO: \"%s\" is too long", name); - } - - if ( tr.numVBOs == MAX_VBOS ) { - ri.Error( ERR_DROP, "R_CreateVBO: MAX_VBOS hit"); - } - - R_IssuePendingRenderCommands(); - - vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); - tr.numVBOs++; - - memset(vbo, 0, sizeof(*vbo)); - - Q_strncpyz(vbo->name, name, sizeof(vbo->name)); - - vbo->vertexesSize = vertexesSize; - - qglGenBuffersARB(1, &vbo->vertexesVBO); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexesSize, vertexes, glUsage); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - - glState.currentVBO = NULL; - - GL_CheckErrors(); - - return vbo; -} - -/* -============ -R_CreateVBO2 -============ -*/ -VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * verts, unsigned int stateBits, vboUsage_t usage) -{ - VBO_t *vbo; - int i; - - byte *data; - int dataSize; - int dataOfs; - - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(!numVertexes) - return NULL; - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long", name); - } - - if ( tr.numVBOs == MAX_VBOS ) { - ri.Error( ERR_DROP, "R_CreateVBO2: MAX_VBOS hit"); - } - - R_IssuePendingRenderCommands(); - - vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); - tr.numVBOs++; - - memset(vbo, 0, sizeof(*vbo)); - - Q_strncpyz(vbo->name, name, sizeof(vbo->name)); - - if (usage == VBO_USAGE_STATIC) - { - // since these vertex attributes are never altered, interleave them - vbo->ofs_xyz = 0; - dataSize = sizeof(verts[0].xyz); - - if(stateBits & ATTR_NORMAL) - { - vbo->ofs_normal = dataSize; - dataSize += sizeof(uint32_t); - } - -#ifdef USE_VERT_TANGENT_SPACE - if(stateBits & ATTR_TANGENT) - { - vbo->ofs_tangent = dataSize; - dataSize += sizeof(uint32_t); - } -#endif - - if(stateBits & ATTR_TEXCOORD) - { - vbo->ofs_st = dataSize; - dataSize += sizeof(verts[0].st); - } - - if(stateBits & ATTR_LIGHTCOORD) - { - vbo->ofs_lightmap = dataSize; - dataSize += sizeof(verts[0].lightmap); - } - - if(stateBits & ATTR_COLOR) - { - vbo->ofs_vertexcolor = dataSize; - dataSize += sizeof(verts[0].vertexColors); - } - - if(stateBits & ATTR_LIGHTDIRECTION) - { - vbo->ofs_lightdir = dataSize; - dataSize += sizeof(uint32_t); - } - - vbo->stride_xyz = dataSize; - vbo->stride_normal = dataSize; -#ifdef USE_VERT_TANGENT_SPACE - vbo->stride_tangent = dataSize; -#endif - vbo->stride_st = dataSize; - vbo->stride_lightmap = dataSize; - vbo->stride_vertexcolor = dataSize; - vbo->stride_lightdir = dataSize; - - // create VBO - dataSize *= numVertexes; - data = ri.Hunk_AllocateTempMemory(dataSize); - dataOfs = 0; - - //ri.Printf(PRINT_ALL, "CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor, - //vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor); - - for (i = 0; i < numVertexes; i++) - { - // xyz - memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz)); - dataOfs += sizeof(verts[i].xyz); - - // normal - if(stateBits & ATTR_NORMAL) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackNormal(verts[i].normal); - - dataOfs += sizeof(uint32_t); - } - -#ifdef USE_VERT_TANGENT_SPACE - // tangent - if(stateBits & ATTR_TANGENT) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackTangent(verts[i].tangent); - - dataOfs += sizeof(uint32_t); - } -#endif - - // vertex texcoords - if(stateBits & ATTR_TEXCOORD) - { - memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st)); - dataOfs += sizeof(verts[i].st); - } - - // feed vertex lightmap texcoords - if(stateBits & ATTR_LIGHTCOORD) - { - memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap)); - dataOfs += sizeof(verts[i].lightmap); - } - - // feed vertex colors - if(stateBits & ATTR_COLOR) - { - memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors)); - dataOfs += sizeof(verts[i].vertexColors); - } - - // feed vertex light directions - if(stateBits & ATTR_LIGHTDIRECTION) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackNormal(verts[i].lightdir); - - dataOfs += sizeof(uint32_t); - } - } - } - else - { - // since these vertex attributes may be changed, put them in flat arrays - dataSize = sizeof(verts[0].xyz); - - if(stateBits & ATTR_NORMAL) - { - dataSize += sizeof(uint32_t); - } - -#ifdef USE_VERT_TANGENT_SPACE - if(stateBits & ATTR_TANGENT) - { - dataSize += sizeof(uint32_t); - } -#endif - - if(stateBits & ATTR_TEXCOORD) - { - dataSize += sizeof(verts[0].st); - } - - if(stateBits & ATTR_LIGHTCOORD) - { - dataSize += sizeof(verts[0].lightmap); - } - - if(stateBits & ATTR_COLOR) - { - dataSize += sizeof(verts[0].vertexColors); - } - - if(stateBits & ATTR_LIGHTDIRECTION) - { - dataSize += sizeof(uint32_t); - } - - // create VBO - dataSize *= numVertexes; - data = ri.Hunk_AllocateTempMemory(dataSize); - dataOfs = 0; - - vbo->ofs_xyz = 0; - vbo->ofs_normal = 0; -#ifdef USE_VERT_TANGENT_SPACE - vbo->ofs_tangent = 0; -#endif - vbo->ofs_st = 0; - vbo->ofs_lightmap = 0; - vbo->ofs_vertexcolor = 0; - vbo->ofs_lightdir = 0; - - vbo->stride_xyz = sizeof(verts[0].xyz); - vbo->stride_normal = sizeof(uint32_t); -#ifdef USE_VERT_TANGENT_SPACE - vbo->stride_tangent = sizeof(uint32_t); -#endif - vbo->stride_vertexcolor = sizeof(verts[0].vertexColors); - vbo->stride_st = sizeof(verts[0].st); - vbo->stride_lightmap = sizeof(verts[0].lightmap); - vbo->stride_lightdir = sizeof(uint32_t); - - //ri.Printf(PRINT_ALL, "2CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor, - //vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor); - - // xyz - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz)); - dataOfs += sizeof(verts[i].xyz); - } - - // normal - if(stateBits & ATTR_NORMAL) - { - vbo->ofs_normal = dataOfs; - for (i = 0; i < numVertexes; i++) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackNormal(verts[i].normal); - - dataOfs += sizeof(uint32_t); - } - } - -#ifdef USE_VERT_TANGENT_SPACE - // tangent - if(stateBits & ATTR_TANGENT) - { - vbo->ofs_tangent = dataOfs; - for (i = 0; i < numVertexes; i++) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackTangent(verts[i].tangent); - - dataOfs += sizeof(uint32_t); - } - } -#endif - - // vertex texcoords - if(stateBits & ATTR_TEXCOORD) - { - vbo->ofs_st = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st)); - dataOfs += sizeof(verts[i].st); - } - } - - // feed vertex lightmap texcoords - if(stateBits & ATTR_LIGHTCOORD) - { - vbo->ofs_lightmap = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap)); - dataOfs += sizeof(verts[i].lightmap); - } - } - - // feed vertex colors - if(stateBits & ATTR_COLOR) - { - vbo->ofs_vertexcolor = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors)); - dataOfs += sizeof(verts[i].vertexColors); - } - } - - // feed vertex lightdirs - if(stateBits & ATTR_LIGHTDIRECTION) - { - vbo->ofs_lightdir = dataOfs; - for (i = 0; i < numVertexes; i++) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackNormal(verts[i].lightdir); - - dataOfs += sizeof(uint32_t); - } - } - } - - - vbo->vertexesSize = dataSize; - - qglGenBuffersARB(1, &vbo->vertexesVBO); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, glUsage); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - - glState.currentVBO = NULL; - - GL_CheckErrors(); - - ri.Hunk_FreeTempMemory(data); - - return vbo; -} - - -/* -============ -R_CreateIBO -============ -*/ -IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, vboUsage_t usage) -{ - IBO_t *ibo; - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateIBO: \"%s\" is too long", name); - } - - if ( tr.numIBOs == MAX_IBOS ) { - ri.Error( ERR_DROP, "R_CreateIBO: MAX_IBOS hit"); - } - - R_IssuePendingRenderCommands(); - - ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); - tr.numIBOs++; - - Q_strncpyz(ibo->name, name, sizeof(ibo->name)); - - ibo->indexesSize = indexesSize; - - qglGenBuffersARB(1, &ibo->indexesVBO); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - - glState.currentIBO = NULL; - - GL_CheckErrors(); - - return ibo; -} - -/* -============ -R_CreateIBO2 -============ -*/ -IBO_t *R_CreateIBO2(const char *name, int numIndexes, glIndex_t * inIndexes, vboUsage_t usage) -{ - IBO_t *ibo; - int i; - - glIndex_t *indexes; - int indexesSize; - - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(!numIndexes) - return NULL; - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateIBO2: \"%s\" is too long", name); - } - - if ( tr.numIBOs == MAX_IBOS ) { - ri.Error( ERR_DROP, "R_CreateIBO2: MAX_IBOS hit"); - } - - R_IssuePendingRenderCommands(); - - ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); - tr.numIBOs++; - - Q_strncpyz(ibo->name, name, sizeof(ibo->name)); - - indexesSize = numIndexes * sizeof(glIndex_t); - indexes = ri.Hunk_AllocateTempMemory(indexesSize); - - for(i = 0; i < numIndexes; i++) - { - indexes[i] = inIndexes[i]; - } - - ibo->indexesSize = indexesSize; - - qglGenBuffersARB(1, &ibo->indexesVBO); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - - glState.currentIBO = NULL; - - GL_CheckErrors(); - - ri.Hunk_FreeTempMemory(indexes); - - return ibo; -} - -/* -============ -R_BindVBO -============ -*/ -void R_BindVBO(VBO_t * vbo) -{ - if(!vbo) - { - //R_BindNullVBO(); - ri.Error(ERR_DROP, "R_BindNullVBO: NULL vbo"); - return; - } - - if(r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- R_BindVBO( %s ) ---\n", vbo->name)); - } - - if(glState.currentVBO != vbo) - { - glState.currentVBO = vbo; - glState.vertexAttribPointersSet = 0; - - glState.vertexAttribsInterpolation = 0; - glState.vertexAttribsOldFrame = 0; - glState.vertexAttribsNewFrame = 0; - glState.vertexAnimation = qfalse; - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); - - backEnd.pc.c_vboVertexBuffers++; - } -} - -/* -============ -R_BindNullVBO -============ -*/ -void R_BindNullVBO(void) -{ - GLimp_LogComment("--- R_BindNullVBO ---\n"); - - if(glState.currentVBO) - { - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glState.currentVBO = NULL; - } - - GL_CheckErrors(); -} - -/* -============ -R_BindIBO -============ -*/ -void R_BindIBO(IBO_t * ibo) -{ - if(!ibo) - { - //R_BindNullIBO(); - ri.Error(ERR_DROP, "R_BindIBO: NULL ibo"); - return; - } - - if(r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- R_BindIBO( %s ) ---\n", ibo->name)); - } - - if(glState.currentIBO != ibo) - { - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - - glState.currentIBO = ibo; - - backEnd.pc.c_vboIndexBuffers++; - } -} - -/* -============ -R_BindNullIBO -============ -*/ -void R_BindNullIBO(void) -{ - GLimp_LogComment("--- R_BindNullIBO ---\n"); - - if(glState.currentIBO) - { - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - glState.currentIBO = NULL; - glState.vertexAttribPointersSet = 0; - } -} - -/* -============ -R_InitVBOs -============ -*/ -void R_InitVBOs(void) -{ - int dataSize; - int offset; - - ri.Printf(PRINT_ALL, "------- R_InitVBOs -------\n"); - - tr.numVBOs = 0; - tr.numIBOs = 0; - - dataSize = sizeof(tess.xyz[0]); - dataSize += sizeof(tess.normal[0]); -#ifdef USE_VERT_TANGENT_SPACE - dataSize += sizeof(tess.tangent[0]); -#endif - dataSize += sizeof(tess.vertexColors[0]); - dataSize += sizeof(tess.texCoords[0][0]) * 2; - dataSize += sizeof(tess.lightdir[0]); - dataSize *= SHADER_MAX_VERTEXES; - - tess.vbo = R_CreateVBO("tessVertexArray_VBO", NULL, dataSize, VBO_USAGE_DYNAMIC); - - offset = 0; - - tess.vbo->ofs_xyz = offset; offset += sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES; - tess.vbo->ofs_normal = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES; -#ifdef USE_VERT_TANGENT_SPACE - tess.vbo->ofs_tangent = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES; -#endif - // these next two are actually interleaved - tess.vbo->ofs_st = offset; - tess.vbo->ofs_lightmap = offset + sizeof(tess.texCoords[0][0]); - offset += sizeof(tess.texCoords[0][0]) * 2 * SHADER_MAX_VERTEXES; - - tess.vbo->ofs_vertexcolor = offset; offset += sizeof(tess.vertexColors[0]) * SHADER_MAX_VERTEXES; - tess.vbo->ofs_lightdir = offset; - - tess.vbo->stride_xyz = sizeof(tess.xyz[0]); - tess.vbo->stride_normal = sizeof(tess.normal[0]); -#ifdef USE_VERT_TANGENT_SPACE - tess.vbo->stride_tangent = sizeof(tess.tangent[0]); -#endif - tess.vbo->stride_vertexcolor = sizeof(tess.vertexColors[0]); - tess.vbo->stride_st = sizeof(tess.texCoords[0][0]) * 2; - tess.vbo->stride_lightmap = sizeof(tess.texCoords[0][0]) * 2; - tess.vbo->stride_lightdir = sizeof(tess.lightdir[0]); - - dataSize = sizeof(tess.indexes[0]) * SHADER_MAX_INDEXES; - - tess.ibo = R_CreateIBO("tessVertexArray_IBO", NULL, dataSize, VBO_USAGE_DYNAMIC); - - R_BindNullVBO(); - R_BindNullIBO(); - - GL_CheckErrors(); -} - -/* -============ -R_ShutdownVBOs -============ -*/ -void R_ShutdownVBOs(void) -{ - int i; - VBO_t *vbo; - IBO_t *ibo; - - ri.Printf(PRINT_ALL, "------- R_ShutdownVBOs -------\n"); - - R_BindNullVBO(); - R_BindNullIBO(); - - - for(i = 0; i < tr.numVBOs; i++) - { - vbo = tr.vbos[i]; - - if(vbo->vertexesVBO) - { - qglDeleteBuffersARB(1, &vbo->vertexesVBO); - } - - //ri.Free(vbo); - } - - for(i = 0; i < tr.numIBOs; i++) - { - ibo = tr.ibos[i]; - - if(ibo->indexesVBO) - { - qglDeleteBuffersARB(1, &ibo->indexesVBO); - } - - //ri.Free(ibo); - } - - tr.numVBOs = 0; - tr.numIBOs = 0; -} - -/* -============ -R_VBOList_f -============ -*/ -void R_VBOList_f(void) -{ - int i; - VBO_t *vbo; - IBO_t *ibo; - int vertexesSize = 0; - int indexesSize = 0; - - ri.Printf(PRINT_ALL, " size name\n"); - ri.Printf(PRINT_ALL, "----------------------------------------------------------\n"); - - for(i = 0; i < tr.numVBOs; i++) - { - vbo = tr.vbos[i]; - - ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vbo->vertexesSize / (1024 * 1024), - (vbo->vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vbo->name); - - vertexesSize += vbo->vertexesSize; - } - - for(i = 0; i < tr.numIBOs; i++) - { - ibo = tr.ibos[i]; - - ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", ibo->indexesSize / (1024 * 1024), - (ibo->indexesSize % (1024 * 1024)) * 100 / (1024 * 1024), ibo->name); - - indexesSize += ibo->indexesSize; - } - - ri.Printf(PRINT_ALL, " %i total VBOs\n", tr.numVBOs); - ri.Printf(PRINT_ALL, " %d.%02d MB total vertices memory\n", vertexesSize / (1024 * 1024), - (vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024)); - - ri.Printf(PRINT_ALL, " %i total IBOs\n", tr.numIBOs); - ri.Printf(PRINT_ALL, " %d.%02d MB total triangle indices memory\n", indexesSize / (1024 * 1024), - (indexesSize % (1024 * 1024)) * 100 / (1024 * 1024)); -} - - -/* -============== -RB_UpdateVBOs - -Adapted from Tess_UpdateVBOs from xreal - -Update the default VBO to replace the client side vertex arrays -============== -*/ -void RB_UpdateVBOs(unsigned int attribBits) -{ - GLimp_LogComment("--- RB_UpdateVBOs ---\n"); - - backEnd.pc.c_dynamicVboDraws++; - - // update the default VBO - if(tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES) - { - R_BindVBO(tess.vbo); - - // orphan old buffer so we don't stall on it - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->vertexesSize, NULL, GL_DYNAMIC_DRAW_ARB); - - if(attribBits & ATTR_BITS) - { - if(attribBits & ATTR_POSITION) - { - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0])); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz); - } - - if(attribBits & ATTR_TEXCOORD || attribBits & ATTR_LIGHTCOORD) - { - // these are interleaved, so we update both if either need it - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords); - } - - if(attribBits & ATTR_NORMAL) - { - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0])); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal); - } - -#ifdef USE_VERT_TANGENT_SPACE - if(attribBits & ATTR_TANGENT) - { - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0])); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent); - } -#endif - - if(attribBits & ATTR_COLOR) - { - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0])); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors); - } - - if(attribBits & ATTR_LIGHTDIRECTION) - { - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0])); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]), tess.lightdir); - } - } - else - { - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal); -#ifdef USE_VERT_TANGENT_SPACE - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent); -#endif - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]), tess.lightdir); - } - - } - - // update the default IBO - if(tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES) - { - R_BindIBO(tess.ibo); - - // orphan old buffer so we don't stall on it - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.ibo->indexesSize, NULL, GL_DYNAMIC_DRAW_ARB); - - qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes); - } -} diff --git a/code/renderergl2/tr_world.c b/code/renderergl2/tr_world.c deleted file mode 100644 index dba15c454c..0000000000 --- a/code/renderergl2/tr_world.c +++ /dev/null @@ -1,858 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - - - -/* -================ -R_CullSurface - -Tries to cull surfaces before they are lighted or -added to the sorting list. -================ -*/ -static qboolean R_CullSurface( msurface_t *surf ) { - if ( r_nocull->integer || surf->cullinfo.type == CULLINFO_NONE) { - return qfalse; - } - - if ( *surf->data == SF_GRID && r_nocurves->integer ) { - return qtrue; - } - - if (surf->cullinfo.type & CULLINFO_PLANE) - { - // Only true for SF_FACE, so treat like its own function - float d; - cullType_t ct; - - if ( !r_facePlaneCull->integer ) { - return qfalse; - } - - ct = surf->shader->cullType; - - if (ct == CT_TWO_SIDED) - { - return qfalse; - } - - // don't cull for depth shadow - /* - if ( tr.viewParms.flags & VPF_DEPTHSHADOW ) - { - return qfalse; - } - */ - - // shadowmaps draw back surfaces - if ( tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW) ) - { - if (ct == CT_FRONT_SIDED) - { - ct = CT_BACK_SIDED; - } - else - { - ct = CT_FRONT_SIDED; - } - } - - // do proper cull for orthographic projection - if (tr.viewParms.flags & VPF_ORTHOGRAPHIC) { - d = DotProduct(tr.viewParms.or.axis[0], surf->cullinfo.plane.normal); - if ( ct == CT_FRONT_SIDED ) { - if (d > 0) - return qtrue; - } else { - if (d < 0) - return qtrue; - } - return qfalse; - } - - d = DotProduct (tr.or.viewOrigin, surf->cullinfo.plane.normal); - - // don't cull exactly on the plane, because there are levels of rounding - // through the BSP, ICD, and hardware that may cause pixel gaps if an - // epsilon isn't allowed here - if ( ct == CT_FRONT_SIDED ) { - if ( d < surf->cullinfo.plane.dist - 8 ) { - return qtrue; - } - } else { - if ( d > surf->cullinfo.plane.dist + 8 ) { - return qtrue; - } - } - - return qfalse; - } - - if (surf->cullinfo.type & CULLINFO_SPHERE) - { - int sphereCull; - - if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) { - sphereCull = R_CullLocalPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius ); - } else { - sphereCull = R_CullPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius ); - } - - if ( sphereCull == CULL_OUT ) - { - return qtrue; - } - } - - if (surf->cullinfo.type & CULLINFO_BOX) - { - int boxCull; - - if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) { - boxCull = R_CullLocalBox( surf->cullinfo.bounds ); - } else { - boxCull = R_CullBox( surf->cullinfo.bounds ); - } - - if ( boxCull == CULL_OUT ) - { - return qtrue; - } - } - - return qfalse; -} - - -/* -==================== -R_DlightSurface - -The given surface is going to be drawn, and it touches a leaf -that is touched by one or more dlights, so try to throw out -more dlights if possible. -==================== -*/ -static int R_DlightSurface( msurface_t *surf, int dlightBits ) { - float d; - int i; - dlight_t *dl; - - if ( surf->cullinfo.type & CULLINFO_PLANE ) - { - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - d = DotProduct( dl->origin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist; - if ( d < -dl->radius || d > dl->radius ) { - // dlight doesn't reach the plane - dlightBits &= ~( 1 << i ); - } - } - } - - if ( surf->cullinfo.type & CULLINFO_BOX ) - { - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - if ( dl->origin[0] - dl->radius > surf->cullinfo.bounds[1][0] - || dl->origin[0] + dl->radius < surf->cullinfo.bounds[0][0] - || dl->origin[1] - dl->radius > surf->cullinfo.bounds[1][1] - || dl->origin[1] + dl->radius < surf->cullinfo.bounds[0][1] - || dl->origin[2] - dl->radius > surf->cullinfo.bounds[1][2] - || dl->origin[2] + dl->radius < surf->cullinfo.bounds[0][2] ) { - // dlight doesn't reach the bounds - dlightBits &= ~( 1 << i ); - } - } - } - - if ( surf->cullinfo.type & CULLINFO_SPHERE ) - { - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - if (!SpheresIntersect(dl->origin, dl->radius, surf->cullinfo.localOrigin, surf->cullinfo.radius)) - { - // dlight doesn't reach the bounds - dlightBits &= ~( 1 << i ); - } - } - } - - switch(*surf->data) - { - case SF_FACE: - case SF_GRID: - case SF_TRIANGLES: - case SF_VBO_MESH: - ((srfBspSurface_t *)surf->data)->dlightBits = dlightBits; - break; - - default: - dlightBits = 0; - break; - } - - if ( dlightBits ) { - tr.pc.c_dlightSurfaces++; - } else { - tr.pc.c_dlightSurfacesCulled++; - } - - return dlightBits; -} - -/* -==================== -R_PshadowSurface - -Just like R_DlightSurface, cull any we can -==================== -*/ -static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) { - float d; - int i; - pshadow_t *ps; - - if ( surf->cullinfo.type & CULLINFO_PLANE ) - { - for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { - if ( ! ( pshadowBits & ( 1 << i ) ) ) { - continue; - } - ps = &tr.refdef.pshadows[i]; - d = DotProduct( ps->lightOrigin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist; - if ( d < -ps->lightRadius || d > ps->lightRadius ) { - // pshadow doesn't reach the plane - pshadowBits &= ~( 1 << i ); - } - } - } - - if ( surf->cullinfo.type & CULLINFO_BOX ) - { - for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { - if ( ! ( pshadowBits & ( 1 << i ) ) ) { - continue; - } - ps = &tr.refdef.pshadows[i]; - if ( ps->lightOrigin[0] - ps->lightRadius > surf->cullinfo.bounds[1][0] - || ps->lightOrigin[0] + ps->lightRadius < surf->cullinfo.bounds[0][0] - || ps->lightOrigin[1] - ps->lightRadius > surf->cullinfo.bounds[1][1] - || ps->lightOrigin[1] + ps->lightRadius < surf->cullinfo.bounds[0][1] - || ps->lightOrigin[2] - ps->lightRadius > surf->cullinfo.bounds[1][2] - || ps->lightOrigin[2] + ps->lightRadius < surf->cullinfo.bounds[0][2] - || BoxOnPlaneSide(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1], &ps->cullPlane) == 2 ) { - // pshadow doesn't reach the bounds - pshadowBits &= ~( 1 << i ); - } - } - } - - if ( surf->cullinfo.type & CULLINFO_SPHERE ) - { - for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { - if ( ! ( pshadowBits & ( 1 << i ) ) ) { - continue; - } - ps = &tr.refdef.pshadows[i]; - if (!SpheresIntersect(ps->viewOrigin, ps->viewRadius, surf->cullinfo.localOrigin, surf->cullinfo.radius) - || DotProduct( surf->cullinfo.localOrigin, ps->cullPlane.normal ) - ps->cullPlane.dist < -surf->cullinfo.radius) - { - // pshadow doesn't reach the bounds - pshadowBits &= ~( 1 << i ); - } - } - } - - switch(*surf->data) - { - case SF_FACE: - case SF_GRID: - case SF_TRIANGLES: - case SF_VBO_MESH: - ((srfBspSurface_t *)surf->data)->pshadowBits = pshadowBits; - break; - - default: - pshadowBits = 0; - break; - } - - if ( pshadowBits ) { - //tr.pc.c_dlightSurfaces++; - } - - return pshadowBits; -} - - -/* -====================== -R_AddWorldSurface -====================== -*/ -static void R_AddWorldSurface( msurface_t *surf, int dlightBits, int pshadowBits ) { - // FIXME: bmodel fog? - - // try to cull before dlighting or adding - if ( R_CullSurface( surf ) ) { - return; - } - - // check for dlighting - if ( dlightBits ) { - dlightBits = R_DlightSurface( surf, dlightBits ); - dlightBits = ( dlightBits != 0 ); - } - - // check for pshadows - /*if ( pshadowBits ) */{ - pshadowBits = R_PshadowSurface( surf, pshadowBits); - pshadowBits = ( pshadowBits != 0 ); - } - - R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits, pshadowBits, surf->cubemapIndex ); -} - -/* -============================================================= - - BRUSH MODELS - -============================================================= -*/ - -/* -================= -R_AddBrushModelSurfaces -================= -*/ -void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) { - bmodel_t *bmodel; - int clip; - model_t *pModel; - int i; - - pModel = R_GetModelByHandle( ent->e.hModel ); - - bmodel = pModel->bmodel; - - clip = R_CullLocalBox( bmodel->bounds ); - if ( clip == CULL_OUT ) { - return; - } - - R_SetupEntityLighting( &tr.refdef, ent ); - R_DlightBmodel( bmodel ); - - for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) { - int surf = bmodel->firstSurface + i; - - if (tr.world->surfacesViewCount[surf] != tr.viewCount) - { - tr.world->surfacesViewCount[surf] = tr.viewCount; - R_AddWorldSurface( tr.world->surfaces + surf, tr.currentEntity->needDlights, 0 ); - } - } -} - - -/* -============================================================= - - WORLD MODEL - -============================================================= -*/ - - -/* -================ -R_RecursiveWorldNode -================ -*/ -static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits, int pshadowBits ) { - - do { - int newDlights[2]; - unsigned int newPShadows[2]; - - // if the node wasn't marked as potentially visible, exit - // pvs is skipped for depth shadows - if (!(tr.viewParms.flags & VPF_DEPTHSHADOW) && node->visCounts[tr.visIndex] != tr.visCounts[tr.visIndex]) { - return; - } - - // if the bounding volume is outside the frustum, nothing - // inside can be visible OPTIMIZE: don't do this all the way to leafs? - - if ( !r_nocull->integer ) { - int r; - - if ( planeBits & 1 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~1; // all descendants will also be in front - } - } - - if ( planeBits & 2 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~2; // all descendants will also be in front - } - } - - if ( planeBits & 4 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~4; // all descendants will also be in front - } - } - - if ( planeBits & 8 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~8; // all descendants will also be in front - } - } - - if ( planeBits & 16 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[4]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~16; // all descendants will also be in front - } - } - } - - if ( node->contents != -1 ) { - break; - } - - // node is just a decision point, so go down both sides - // since we don't care about sort orders, just go positive to negative - - // determine which dlights are needed - newDlights[0] = 0; - newDlights[1] = 0; - if ( dlightBits ) { - int i; - - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - dlight_t *dl; - float dist; - - if ( dlightBits & ( 1 << i ) ) { - dl = &tr.refdef.dlights[i]; - dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist; - - if ( dist > -dl->radius ) { - newDlights[0] |= ( 1 << i ); - } - if ( dist < dl->radius ) { - newDlights[1] |= ( 1 << i ); - } - } - } - } - - newPShadows[0] = 0; - newPShadows[1] = 0; - if ( pshadowBits ) { - int i; - - for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { - pshadow_t *shadow; - float dist; - - if ( pshadowBits & ( 1 << i ) ) { - shadow = &tr.refdef.pshadows[i]; - dist = DotProduct( shadow->lightOrigin, node->plane->normal ) - node->plane->dist; - - if ( dist > -shadow->lightRadius ) { - newPShadows[0] |= ( 1 << i ); - } - if ( dist < shadow->lightRadius ) { - newPShadows[1] |= ( 1 << i ); - } - } - } - } - - // recurse down the children, front side first - R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0], newPShadows[0] ); - - // tail recurse - node = node->children[1]; - dlightBits = newDlights[1]; - pshadowBits = newPShadows[1]; - } while ( 1 ); - - { - // leaf node, so add mark surfaces - int c; - int surf, *view; - - tr.pc.c_leafs++; - - // add to z buffer bounds - if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) { - tr.viewParms.visBounds[0][0] = node->mins[0]; - } - if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) { - tr.viewParms.visBounds[0][1] = node->mins[1]; - } - if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) { - tr.viewParms.visBounds[0][2] = node->mins[2]; - } - - if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) { - tr.viewParms.visBounds[1][0] = node->maxs[0]; - } - if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) { - tr.viewParms.visBounds[1][1] = node->maxs[1]; - } - if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) { - tr.viewParms.visBounds[1][2] = node->maxs[2]; - } - - // add merged and unmerged surfaces - if (tr.world->viewSurfaces && !r_nocurves->integer) - view = tr.world->viewSurfaces + node->firstmarksurface; - else - view = tr.world->marksurfaces + node->firstmarksurface; - - c = node->nummarksurfaces; - while (c--) { - // just mark it as visible, so we don't jump out of the cache derefencing the surface - surf = *view; - if (surf < 0) - { - if (tr.world->mergedSurfacesViewCount[-surf - 1] != tr.viewCount) - { - tr.world->mergedSurfacesViewCount[-surf - 1] = tr.viewCount; - tr.world->mergedSurfacesDlightBits[-surf - 1] = dlightBits; - tr.world->mergedSurfacesPshadowBits[-surf - 1] = pshadowBits; - } - else - { - tr.world->mergedSurfacesDlightBits[-surf - 1] |= dlightBits; - tr.world->mergedSurfacesPshadowBits[-surf - 1] |= pshadowBits; - } - } - else - { - if (tr.world->surfacesViewCount[surf] != tr.viewCount) - { - tr.world->surfacesViewCount[surf] = tr.viewCount; - tr.world->surfacesDlightBits[surf] = dlightBits; - tr.world->surfacesPshadowBits[surf] = pshadowBits; - } - else - { - tr.world->surfacesDlightBits[surf] |= dlightBits; - tr.world->surfacesPshadowBits[surf] |= pshadowBits; - } - } - view++; - } - } - -} - - -/* -=============== -R_PointInLeaf -=============== -*/ -static mnode_t *R_PointInLeaf( const vec3_t p ) { - mnode_t *node; - float d; - cplane_t *plane; - - if ( !tr.world ) { - ri.Error (ERR_DROP, "R_PointInLeaf: bad model"); - } - - node = tr.world->nodes; - while( 1 ) { - if (node->contents != -1) { - break; - } - plane = node->plane; - d = DotProduct (p,plane->normal) - plane->dist; - if (d > 0) { - node = node->children[0]; - } else { - node = node->children[1]; - } - } - - return node; -} - -/* -============== -R_ClusterPVS -============== -*/ -static const byte *R_ClusterPVS (int cluster) { - if (!tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) { - return tr.world->novis; - } - - return tr.world->vis + cluster * tr.world->clusterBytes; -} - -/* -================= -R_inPVS -================= -*/ -qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) { - mnode_t *leaf; - byte *vis; - - leaf = R_PointInLeaf( p1 ); - vis = ri.CM_ClusterPVS( leaf->cluster ); // why not R_ClusterPVS ?? - leaf = R_PointInLeaf( p2 ); - - if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) { - return qfalse; - } - return qtrue; -} - -/* -=============== -R_MarkLeaves - -Mark the leaves and nodes that are in the PVS for the current -cluster -=============== -*/ -static void R_MarkLeaves (void) { - const byte *vis; - mnode_t *leaf, *parent; - int i; - int cluster; - - // lockpvs lets designers walk around to determine the - // extent of the current pvs - if ( r_lockpvs->integer ) { - return; - } - - // current viewcluster - leaf = R_PointInLeaf( tr.viewParms.pvsOrigin ); - cluster = leaf->cluster; - - // if the cluster is the same and the area visibility matrix - // hasn't changed, we don't need to mark everything again - - for(i = 0; i < MAX_VISCOUNTS; i++) - { - if(tr.visClusters[i] == cluster) - { - //tr.visIndex = i; - break; - } - } - - // if r_showcluster was just turned on, remark everything - if(i != MAX_VISCOUNTS && !tr.refdef.areamaskModified && !r_showcluster->modified)// && !r_dynamicBspOcclusionCulling->modified) - { - if(tr.visClusters[i] != tr.visClusters[tr.visIndex] && r_showcluster->integer) - { - ri.Printf(PRINT_ALL, "found cluster:%i area:%i index:%i\n", cluster, leaf->area, i); - } - tr.visIndex = i; - return; - } - - // if the areamask was modified, invalidate all visclusters - // this caused doors to open into undrawn areas - if (tr.refdef.areamaskModified) - { - memset(tr.visClusters, -2, sizeof(tr.visClusters)); - } - - tr.visIndex = (tr.visIndex + 1) % MAX_VISCOUNTS; - tr.visCounts[tr.visIndex]++; - tr.visClusters[tr.visIndex] = cluster; - - if ( r_showcluster->modified || r_showcluster->integer ) { - r_showcluster->modified = qfalse; - if ( r_showcluster->integer ) { - ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area ); - } - } - - // set all nodes to visible if there is no vis - // this caused some levels to simply not render - if (r_novis->integer || !tr.world->vis || tr.visClusters[tr.visIndex] == -1) { - for (i=0 ; inumnodes ; i++) { - if (tr.world->nodes[i].contents != CONTENTS_SOLID) { - tr.world->nodes[i].visCounts[tr.visIndex] = tr.visCounts[tr.visIndex]; - } - } - return; - } - - vis = R_ClusterPVS(tr.visClusters[tr.visIndex]); - - for (i=0,leaf=tr.world->nodes ; inumnodes ; i++, leaf++) { - cluster = leaf->cluster; - if ( cluster < 0 || cluster >= tr.world->numClusters ) { - continue; - } - - // check general pvs - if ( !(vis[cluster>>3] & (1<<(cluster&7))) ) { - continue; - } - - // check for door connection - if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) { - continue; // not visible - } - - parent = leaf; - do { - if(parent->visCounts[tr.visIndex] == tr.visCounts[tr.visIndex]) - break; - parent->visCounts[tr.visIndex] = tr.visCounts[tr.visIndex]; - parent = parent->parent; - } while (parent); - } -} - - -/* -============= -R_AddWorldSurfaces -============= -*/ -void R_AddWorldSurfaces (void) { - int planeBits, dlightBits, pshadowBits; - - if ( !r_drawworld->integer ) { - return; - } - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return; - } - - tr.currentEntityNum = REFENTITYNUM_WORLD; - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - - // determine which leaves are in the PVS / areamask - if (!(tr.viewParms.flags & VPF_DEPTHSHADOW)) - R_MarkLeaves (); - - // clear out the visible min/max - ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] ); - - // perform frustum culling and flag all the potentially visible surfaces - if ( tr.refdef.num_dlights > 32 ) { - tr.refdef.num_dlights = 32 ; - } - - if ( tr.refdef.num_pshadows > 32 ) { - tr.refdef.num_pshadows = 32 ; - } - - planeBits = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 31 : 15; - - if ( tr.viewParms.flags & VPF_DEPTHSHADOW ) - { - dlightBits = 0; - pshadowBits = 0; - } - else if ( !(tr.viewParms.flags & VPF_SHADOWMAP) ) - { - dlightBits = ( 1 << tr.refdef.num_dlights ) - 1; - pshadowBits = ( 1 << tr.refdef.num_pshadows ) - 1; - } - else - { - dlightBits = ( 1 << tr.refdef.num_dlights ) - 1; - pshadowBits = 0; - } - - R_RecursiveWorldNode( tr.world->nodes, planeBits, dlightBits, pshadowBits); - - // now add all the potentially visible surfaces - // also mask invisible dlights for next frame - { - int i; - - tr.refdef.dlightMask = 0; - - for (i = 0; i < tr.world->numWorldSurfaces; i++) - { - if (tr.world->surfacesViewCount[i] != tr.viewCount) - continue; - - R_AddWorldSurface( tr.world->surfaces + i, tr.world->surfacesDlightBits[i], tr.world->surfacesPshadowBits[i] ); - tr.refdef.dlightMask |= tr.world->surfacesDlightBits[i]; - } - for (i = 0; i < tr.world->numMergedSurfaces; i++) - { - if (tr.world->mergedSurfacesViewCount[i] != tr.viewCount) - continue; - - R_AddWorldSurface( tr.world->mergedSurfaces + i, tr.world->mergedSurfacesDlightBits[i], tr.world->mergedSurfacesPshadowBits[i] ); - tr.refdef.dlightMask |= tr.world->mergedSurfacesDlightBits[i]; - } - - tr.refdef.dlightMask = ~tr.refdef.dlightMask; - } -} diff --git a/code/sys/sys_main.c b/code/sys/sys_main.c index ea3cf21e59..8e08ecbc2d 100644 --- a/code/sys/sys_main.c +++ b/code/sys/sys_main.c @@ -161,6 +161,12 @@ qboolean Sys_WritePIDFile( void ) FILE *f; qboolean stale = qfalse; +#ifdef WINFOUR + // leilei - workaround to avoid crashes on WinNT4/W9X + if ( pidFiles ) + return qfalse; +#endif + if( pidFile == NULL ) return qfalse; diff --git a/code/sys/sys_win32.c b/code/sys/sys_win32.c index 3288105fe0..5cb3bea9f7 100644 --- a/code/sys/sys_win32.c +++ b/code/sys/sys_win32.c @@ -170,7 +170,10 @@ Sys_RandomBytes qboolean Sys_RandomBytes( byte *string, int len ) { HCRYPTPROV prov; - + // leilei - NT 3.51 doesn't have this in ADVAPI32, so leave this out of WINFOUR +#ifdef WINFOUR + return qfalse; +#else if( !CryptAcquireContext( &prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) ) { @@ -183,6 +186,7 @@ qboolean Sys_RandomBytes( byte *string, int len ) } CryptReleaseContext( prov, 0 ); return qtrue; +#endif } /*