From 3acda727d22a498d50fd0dbe516daac4b10af304 Mon Sep 17 00:00:00 2001 From: OM Date: Mon, 29 May 2023 14:27:36 +0200 Subject: [PATCH] Added full sprite support --- code/renderer/tr_backend.c | 96 ++++++++++++++++++++ code/renderer/tr_cmds.c | 23 +++++ code/renderer/tr_image.c | 2 + code/renderer/tr_main.c | 180 +++++++++++++++++++++++++++++++------ code/renderer/tr_scene.c | 32 ++++++- code/renderer/tr_sprite.c | 152 ++++++++++++++++++++++++++++++- 6 files changed, 456 insertions(+), 29 deletions(-) diff --git a/code/renderer/tr_backend.c b/code/renderer/tr_backend.c index 6d015323..88d6b94f 100644 --- a/code/renderer/tr_backend.c +++ b/code/renderer/tr_backend.c @@ -916,6 +916,74 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { #endif } +/* +================== +RB_RenderSpriteSurfList +================== +*/ +void RB_RenderSpriteSurfList(drawSurf_t* drawSurfs, int numDrawSurfs) { + shader_t *shader; + shader_t *oldShader; + qboolean depthRange; + qboolean oldDepthRange; + int i; + drawSurf_t *drawSurf; + + backEnd.currentEntity = &tr.worldEntity; + backEnd.currentStaticModel = 0; + + backEnd.pc.c_surfaces += numDrawSurfs; + backEnd.ori = backEnd.viewParms.world; + + oldShader = NULL; + depthRange = qfalse; + oldDepthRange = qfalse; + + for (i = 0, drawSurf = drawSurfs; i < numDrawSurfs; i++, drawSurf++) { + shader = tr.sortedShaders[((refSprite_t*)drawSurf->surface)->shaderNum]; + depthRange = (((refSprite_t*)drawSurf->surface)->renderfx & RF_DEPTHHACK) != 0; + + if ((shader != oldShader || (oldShader->flags & RF_THIRD_PERSON) != 0) && !shader->entityMergable) + { + if (oldShader) { + RB_EndSurface(); + } + + RB_BeginSurface(shader); + oldShader = shader; + } + + qglLoadMatrixf(backEnd.ori.modelMatrix); + + if (oldDepthRange != depthRange) + { + if (depthRange) { + qglDepthRange(0.0, 0.3); + } else { + qglDepthRange(0.0, 1.0); + } + + oldDepthRange = depthRange; + } + + backEnd.shaderStartTime = ((refSprite_t*)drawSurf->surface)->shaderTime; + + // add the triangles for this surface + rb_surfaceTable[*drawSurf->surface](drawSurf->surface); + } + + if (oldShader) { + RB_EndSurface(); + } + + // go back to the world modelview matrix + qglLoadMatrixf(backEnd.viewParms.world.modelMatrix); + // go back to the previous depth range + if (depthRange) { + qglDepthRange(0.0, 1.0); + } +} + /* ============================================================================ @@ -1153,6 +1221,31 @@ const void *RB_DrawSurfs( const void *data ) { } +/* +============= +RB_DrawSurfs + +============= +*/ +const void* RB_SpriteSurfs(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_RenderSpriteSurfList(cmd->drawSurfs, cmd->numDrawSurfs); + + return (const void*)(cmd + 1); +} + + /* ============= RB_DrawBuffer @@ -1319,6 +1412,9 @@ void RB_ExecuteRenderCommands( const void *data ) { case RC_DRAW_SURFS: data = RB_DrawSurfs( data ); break; + case RC_SPRITE_SURFS: + data = RB_SpriteSurfs( data ); + break; case RC_DRAW_BUFFER: data = RB_DrawBuffer( data ); break; diff --git a/code/renderer/tr_cmds.c b/code/renderer/tr_cmds.c index cfedc2cc..466f909d 100644 --- a/code/renderer/tr_cmds.c +++ b/code/renderer/tr_cmds.c @@ -254,6 +254,29 @@ void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) { } +/* +============= +R_AddSpriteSurfCmd + +============= +*/ +void R_AddSpriteSurfCmd(drawSurf_t* drawSurfs, int numDrawSurfs) { + drawSurfsCommand_t* cmd; + + cmd = R_GetCommandBuffer(sizeof(*cmd)); + if (!cmd) { + return; + } + cmd->commandId = RC_SPRITE_SURFS; + + cmd->drawSurfs = drawSurfs; + cmd->numDrawSurfs = numDrawSurfs; + + cmd->refdef = tr.refdef; + cmd->viewParms = tr.viewParms; +} + + /* ============= RE_SetColor diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index 9d41f5ab..826e44d5 100644 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -2526,6 +2526,8 @@ image_t* R_FindImageFile(const char* name, qboolean mipmap, qboolean allowPicmip // // load the pic from disk // + numMipmaps = mipmap; + iMipmapsAvailable = 0; R_LoadImage(name, &pic, &width, &height, &hasAlpha, &glCompressMode, &numMipmaps, &iMipmapsAvailable); if (pic == NULL) { return NULL; diff --git a/code/renderer/tr_main.c b/code/renderer/tr_main.c index 3ff5fb7c..eb991adb 100644 --- a/code/renderer/tr_main.c +++ b/code/renderer/tr_main.c @@ -293,6 +293,29 @@ void myGlMultMatrix( const float *a, const float *b, float *out ) { } } +void R_AdjustVisBoundsForSprite(refSprite_t* ent, viewParms_t* viewParms, orientationr_t* or ) +{ + if (tr.viewParms.visBounds[0][0] > ent->origin[0] - ent->scale) { + tr.viewParms.visBounds[0][0] = ent->origin[0] - ent->scale; + } + if (tr.viewParms.visBounds[0][1] > ent->origin[1] - ent->scale) { + tr.viewParms.visBounds[0][1] = ent->origin[1] - ent->scale; + } + if (tr.viewParms.visBounds[0][2] > ent->origin[2] - ent->scale) { + tr.viewParms.visBounds[0][2] = ent->origin[2] - ent->scale; + } + + if (tr.viewParms.visBounds[1][0] < ent->origin[0] + ent->scale) { + tr.viewParms.visBounds[1][0] = ent->origin[0] + ent->scale; + } + if (tr.viewParms.visBounds[1][1] < ent->origin[1] + ent->scale) { + tr.viewParms.visBounds[1][1] = ent->origin[1] + ent->scale; + } + if (tr.viewParms.visBounds[1][2] < ent->origin[2] + ent->scale) { + tr.viewParms.visBounds[1][2] = ent->origin[2] + ent->scale; + } +} + /* ================= R_RotateForEntity @@ -1318,6 +1341,25 @@ void R_AddDrawSurf(surfaceType_t* surface, shader_t* shader, int dlightMap) { tr.refdef.numDrawSurfs++; } +/* +================= +R_AddSpriteSurf +================= +*/ +void R_AddSpriteSurf(surfaceType_t* surface, shader_t* shader, float zDistance) +{ + int index; + + if (zDistance > MAX_SPRITE_DIST_SQUARED) { + zDistance = MAX_SPRITE_DIST_SQUARED; + } + + index = tr.refdef.numSpriteSurfs % MAX_SPRITES; + tr.refdef.spriteSurfs[index].sort = (int)(MAX_SPRITE_DIST_SQUARED - zDistance) | (shader->sortedIndex << QSORT_SHADERNUM_SHIFT); + tr.refdef.spriteSurfs[index].surface = surface; + tr.refdef.numSpriteSurfs++; +} + /* ================= R_DecomposeSort @@ -1335,7 +1377,7 @@ void R_DecomposeSort(unsigned int sort, int* entityNum, shader_t** shader, int* R_SortDrawSurfs ================= */ -void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { +void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs, drawSurf_t *spriteSurfs, int numSpriteSurfs ) { shader_t *shader; int entityNum; int dlighted; @@ -1351,39 +1393,49 @@ void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { // 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; - } + // the first surfaces, not the last ones + if (numDrawSurfs > MAX_DRAWSURFS) { + numDrawSurfs = MAX_DRAWSURFS; + } + if (numSpriteSurfs > MAX_SPRITESURFS) { + numSpriteSurfs = MAX_SPRITESURFS; + } // sort the drawsurfs by sort type, then orientation, then shader qsortFast (drawSurfs, numDrawSurfs, sizeof(drawSurf_t) ); + qsortFast (spriteSurfs, numSpriteSurfs, sizeof(drawSurf_t) ); - // 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, &dlighted, &bStaticModel); + R_Sky_Render(); - if ( shader->sort > SS_PORTAL ) { - break; - } + if (!tr.viewParms.isPortal) + { + // 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, &dlighted, &bStaticModel); - // 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; + 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 } - break; // only one mirror view at a time } } - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); + R_AddDrawSurfCmd(drawSurfs, numDrawSurfs); + R_AddSpriteSurfCmd(spriteSurfs, numSpriteSurfs); } /* @@ -1470,6 +1522,55 @@ void R_AddEntitySurfaces (void) { } +void R_AddSpriteSurfaces() +{ + refSprite_t* sprite; + vec3_t delta; + + if (!r_drawsprites->integer) { + return; + } + + for (tr.currentSpriteNum = 0; tr.currentSpriteNum < tr.refdef.num_sprites; ++tr.currentSpriteNum) + { + sprite = &tr.refdef.sprites[tr.currentSpriteNum]; + + if (tr.portalsky.inUse) + { + if ((sprite->renderfx & RF_SKYENTITY) == 0) { + continue; + } + } + else if ((sprite->renderfx & RF_SKYENTITY) != 0) + { + continue; + } + + if (tr.viewParms.isPortal) + { + if (!(sprite->renderfx & (RF_SHADOW_PLANE | RF_WRAP_FRAMES))) { + continue; + } + } + else if (sprite->renderfx & RF_SHADOW_PLANE) { + continue; + } + + tr.currentEntityNum = ENTITYNUM_WORLD; + tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT; + if (sprite->hModel && sprite->hModel < tr.numModels) { + tr.currentModel = &tr.models[sprite->hModel]; + } else { + tr.currentModel = &tr.models[0]; + } + + R_AdjustVisBoundsForSprite(&tr.refdef.sprites[tr.currentSpriteNum], &tr.viewParms, &tr.ori ); + sprite->shaderNum = tr.currentModel->d.sprite->shader->sortedIndex; + + VectorSubtract(sprite->origin, tr.refdef.vieworg, delta); + R_AddSpriteSurf(&sprite->surftype, tr.currentModel->d.sprite->shader, VectorLengthSquared(delta)); + } +} /* ==================== @@ -1478,17 +1579,24 @@ R_GenerateDrawSurfs */ void R_GenerateDrawSurfs( void ) { R_AddWorldSurfaces (); + if (!(tr.refdef.rdflags & RDF_NOWORLDMODEL)) { + R_AddSwipeSurfaces(); + } R_AddPolygonSurfaces(); + R_AddTerrainMarkSurfaces(); + + R_AddEntitySurfaces(); + + R_AddSpriteSurfaces(); + // 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 R_SetupProjection (); - - R_AddEntitySurfaces (); } /* @@ -1641,6 +1749,15 @@ void R_DrawDebugLines(void) { // FIXME: stub } +/* +================ +R_DrawDebugLines +================ +*/ +void R_DrawDebugStrings(void) { + // FIXME: stub +} + /* ================ R_RenderView @@ -1651,6 +1768,7 @@ or a mirror / remote location */ void R_RenderView (viewParms_t *parms) { int firstDrawSurf; + int firstSpriteSurf; if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) { return; @@ -1663,6 +1781,7 @@ void R_RenderView (viewParms_t *parms) { tr.viewParms.frameCount = tr.frameCount; firstDrawSurf = tr.refdef.numDrawSurfs; + firstSpriteSurf = tr.refdef.numSpriteSurfs; tr.viewCount++; @@ -1673,9 +1792,16 @@ void R_RenderView (viewParms_t *parms) { R_Sky_Reset(); + R_DrawDebugStrings(); + R_GenerateDrawSurfs(); - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); + R_SortDrawSurfs( + tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf, + tr.refdef.spriteSurfs + firstSpriteSurf, tr.refdef.numSpriteSurfs - firstSpriteSurf + ); + + R_DrawDebugLines(); // draw main system development information (surface outlines, etc) R_DebugGraphics(); diff --git a/code/renderer/tr_scene.c b/code/renderer/tr_scene.c index 2db991c9..5a28e18b 100644 --- a/code/renderer/tr_scene.c +++ b/code/renderer/tr_scene.c @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tiki.h" int r_firstSceneDrawSurf; +int r_firstSceneSpriteSurf; int r_numdlights; int r_firstSceneDlight; @@ -62,6 +63,7 @@ void R_ToggleSmpFrame( void ) { backEndData[tr.smpFrame]->commands.used = 0; r_firstSceneDrawSurf = 0; + r_firstSceneSpriteSurf = 0; r_numdlights = 0; r_firstSceneDlight = 0; @@ -245,7 +247,31 @@ void RE_AddRefEntityToScene( const refEntity_t *ent, int parentEntityNumber) { } void RE_AddRefSpriteToScene(const refEntity_t* ent) { - // FIXME: unimplemented + refSprite_t* spr; + int i; + + if (!tr.registered) { + return; + } + + if (r_numsprites >= MAX_SPRITES) { + return; + } + + spr = &backEndData[tr.smpFrame]->sprites[r_numsprites]; + VectorCopy(ent->origin, spr->origin); + spr->surftype = SF_SPRITE; + spr->hModel = ent->hModel; + spr->scale = ent->scale; + spr->renderfx = ent->renderfx; + spr->shaderTime = ent->shaderTime; + AxisCopy(ent->axis, spr->axis); + + for (i = 0; i < 4; ++i) { + spr->shaderRGBA[i] = ent->shaderRGBA[i]; + } + + ++r_numsprites; } /* @@ -388,6 +414,9 @@ void RE_RenderScene( const refdef_t *fd ) { tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs; + tr.refdef.numSpriteSurfs = r_firstSceneSpriteSurf; + tr.refdef.spriteSurfs = backEndData[tr.smpFrame]->spriteSurfs; + tr.refdef.num_entities = r_numentities - r_firstSceneEntity; tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity]; @@ -456,6 +485,7 @@ void RE_RenderScene( const refdef_t *fd ) { // the next scene rendered in this frame will tack on after this one r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; + r_firstSceneSpriteSurf = tr.refdef.numSpriteSurfs; r_firstSceneEntity = r_numentities; r_firstSceneSprite = r_numsprites; r_firstSceneDlight = r_numdlights; diff --git a/code/renderer/tr_sprite.c b/code/renderer/tr_sprite.c index 17f0bfcc..05ef5753 100644 --- a/code/renderer/tr_sprite.c +++ b/code/renderer/tr_sprite.c @@ -56,11 +56,161 @@ sprite_t *SPR_RegisterSprite(const char *name) return 0; } +static int CullSprite(const vec3_t* points) { + int i, j; + + for (i = 0; i < backEnd.viewParms.fog.extrafrustums + 4; i++) { + for (j = 0; j < 4; j++) { + if (DotProduct(points[j], backEnd.viewParms.frustum[i].normal) - backEnd.viewParms.frustum[i].dist > 0.0f) { + break; + } + } + + if (j == 4) { + return CULL_CLIP; + } + } + + return CULL_IN; +} + /* ===================== RB_DrawSprite ===================== */ void RB_DrawSprite( const refSprite_t *spr ) { - // FIXME: stub + model_t* model; + vec3_t norm; + vec3_t up, right; + vec3_t points[4]; + float org_x, org_y; + float scale; + + if (!spr->hModel) + { + ri.Printf(PRINT_WARNING, "No model found for Sprite\n"); + return; + } + + model = tr.models; + if (spr->hModel > 0 && spr->hModel < tr.numModels) { + model = &tr.models[spr->hModel]; + } + + scale = spr->scale * model->d.sprite->scale; + + switch (model->d.sprite->shader->sprite.type) + { + case SPRITE_PARALLEL_ORIENTED: + { + float invmag; + float cr, sr; + int i; + + invmag = 1.0 / sqrt(spr->axis[1][2] * spr->axis[1][2] + spr->axis[1][1] * spr->axis[1][1]); + + cr = invmag * spr->axis[1][1]; + sr = invmag * spr->axis[1][2]; + + for (i = 0; i < 3; i++) + { + up[i] = backEnd.viewParms.ori.axis[2][i] * cr - backEnd.viewParms.ori.axis[1][i] * sr; + right[i] = backEnd.viewParms.ori.axis[1][i] * cr + backEnd.viewParms.ori.axis[2][i] * sr; + } + } + break; + case SPRITE_PARALLEL: + VectorCopy(backEnd.viewParms.ori.axis[2], up); + if (!backEnd.viewParms.isMirror) { + VectorNegate(backEnd.viewParms.ori.axis[1], right); + } else { + VectorCopy(backEnd.viewParms.ori.axis[1], right); + } + break; + case SPRITE_ORIENTED: + VectorCopy(spr->axis[1], right); + VectorCopy(spr->axis[2], up); + break; + case SPRITE_PARALLEL_UPRIGHT: + VectorCopy(backEnd.viewParms.ori.axis[0], norm); + VectorCopy(backEnd.viewParms.ori.axis[1], right); + VectorCopy(backEnd.viewParms.ori.axis[2], up); + if (backEnd.viewParms.ori.axis[0][2] > 0.999) { + return; + } else if (backEnd.viewParms.ori.axis[0][2] < -0.999) { + return; + } + + VectorSet(up, 0.0f, 0.0f, 1.0f); + VectorSet(right, backEnd.viewParms.ori.axis[0][1], -backEnd.viewParms.ori.axis[0][0], 0.0f); + VectorNormalize(right); + VectorSet(norm, -right[1], right[0], 0.0f); + break; + } + + org_x = model->d.sprite->origin_x * scale; + org_y = model->d.sprite->origin_y * scale; + + VectorScale(up, org_y, up); + VectorScale(right, org_x, right); + + points[0][0] = spr->origin[0] + up[0] - right[0]; + points[1][0] = spr->origin[0] + up[0] + right[0]; + points[2][0] = spr->origin[0] - up[0] - right[0]; + points[3][0] = spr->origin[0] - up[0] + right[0]; + + points[0][1] = spr->origin[1] + up[1] - right[1]; + points[1][1] = spr->origin[1] + up[1] + right[1]; + points[2][1] = spr->origin[1] - up[1] - right[1]; + points[3][1] = spr->origin[1] - up[1] + right[1]; + + points[0][2] = spr->origin[2] + up[2] - right[2]; + points[1][2] = spr->origin[2] + up[2] + right[2]; + points[2][2] = spr->origin[2] - up[2] - right[2]; + points[3][2] = spr->origin[2] - up[2] + right[2]; + + if (CullSprite(points) == CULL_OUT) { + return; + } + + RB_CHECKOVERFLOW(4, 6); + + memcpy(tess.vertexColors[tess.numVertexes], spr->shaderRGBA, sizeof(byte) * 4); + memcpy(tess.vertexColors[tess.numVertexes + 1], spr->shaderRGBA, sizeof(byte) * 4); + memcpy(tess.vertexColors[tess.numVertexes + 2], spr->shaderRGBA, sizeof(byte) * 4); + memcpy(tess.vertexColors[tess.numVertexes + 3], spr->shaderRGBA, sizeof(byte) * 4); + + tess.vertexColorValid = qtrue; + tess.texCoords[tess.numVertexes][0][0] = 0.0f; + tess.texCoords[tess.numVertexes][0][1] = 0.0f; + tess.texCoords[tess.numVertexes + 1][0][0] = 1.0f; + tess.texCoords[tess.numVertexes + 1][0][1] = 0.0f; + tess.texCoords[tess.numVertexes + 2][0][0] = 0.0f; + tess.texCoords[tess.numVertexes + 2][0][1] = 1.0f; + tess.texCoords[tess.numVertexes + 3][0][0] = 1.0f; + tess.texCoords[tess.numVertexes + 3][0][1] = 1.0f; + + tess.xyz[tess.numVertexes][0] = points[0][0]; + tess.xyz[tess.numVertexes][1] = points[0][1]; + tess.xyz[tess.numVertexes][2] = points[0][2]; + tess.xyz[tess.numVertexes + 1][0] = points[1][0]; + tess.xyz[tess.numVertexes + 1][1] = points[1][1]; + tess.xyz[tess.numVertexes + 1][2] = points[1][2]; + tess.xyz[tess.numVertexes + 2][0] = points[2][0]; + tess.xyz[tess.numVertexes + 2][1] = points[2][1]; + tess.xyz[tess.numVertexes + 2][2] = points[2][2]; + tess.xyz[tess.numVertexes + 3][0] = points[3][0]; + tess.xyz[tess.numVertexes + 3][1] = points[3][1]; + tess.xyz[tess.numVertexes + 3][2] = points[3][2]; + + tess.indexes[tess.numIndexes] = tess.numVertexes + 2; + tess.indexes[tess.numIndexes + 1] = tess.numVertexes + 1; + tess.indexes[tess.numIndexes + 2] = tess.numVertexes; + tess.indexes[tess.numIndexes + 3] = tess.numVertexes + 2; + tess.indexes[tess.numIndexes + 4] = tess.numVertexes + 3; + tess.indexes[tess.numIndexes + 5] = tess.numVertexes + 1; + + tess.numVertexes += 4; + tess.numIndexes += 6; }