Example #1
0
/**
 * @brief RE_AddCoronaToScene
 * @param[in] org
 * @param[in] r
 * @param[in] g
 * @param[in] b
 * @param[in] scale
 * @param[in] id
 * @param[in] visible
 */
void RE_AddCoronaToScene(const vec3_t org, float r, float g, float b, float scale, int id, qboolean visible)
{
	corona_t *cor;

	if (!tr.registered)
	{
		return;
	}

	if (!visible)
	{
		return;
	}

	if (r_numcoronas >= MAX_CORONAS)
	{
		Ren_Developer("WARNING RE_AddCoronaToScene: Dropping corona, reached MAX_CORONAS\n");
		return;
	}

	cor = &backEndData->coronas[r_numcoronas++];
	VectorCopy(org, cor->origin);
	cor->color[0] = r;
	cor->color[1] = g;
	cor->color[2] = b;
	cor->scale    = scale;
	cor->id       = id;
	cor->visible  = visible;
}
Example #2
0
/**
 * @brief GetMDVSurfaceShader
 * @param[in] ent
 * @param[in] mdvSurface
 * @return
 */
static shader_t *GetMDVSurfaceShader(const trRefEntity_t *ent, mdvSurface_t *mdvSurface)
{
	shader_t *shader = 0;

	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, mdvSurface->name))
			{
				shader = skin->surfaces[j].shader;
				break;
			}
		}
		if (shader == tr.defaultShader)
		{
			Ren_Developer("WARNING: no shader for surface %s in skin %s\n", mdvSurface->name, skin->name);
		}
		else if (shader->defaultShader)
		{
			Ren_Developer("WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
		}
	}
	else
	{
		shader = mdvSurface->shader;
	}

	return shader;
}
Example #3
0
void QDECL Com_DPrintf(const char *msg, ...)
{
	va_list argptr;
	char    text[1024];

	va_start(argptr, msg);
	Q_vsnprintf(text, sizeof(text), msg, argptr);
	va_end(argptr);

	Ren_Developer("%s", text);
}
Example #4
0
void printBits(size_t const size, void const *const ptr)
{
	unsigned char *b = (unsigned char *) ptr;
	unsigned char byte;
	int           i, j;

	for (i = size - 1; i >= 0; i--)
	{
		for (j = 7; j >= 0; j--)
		{
			byte   = b[i] & (1 << j);
			byte >>= j;
			Ren_Developer("%u", byte);
		}
	}
}
Example #5
0
void R_ShutdownFBOs(void)
{
	int   i, j;
	FBO_t *fbo;

	Ren_Developer("------- R_ShutdownFBOs -------\n");

	if (!glConfig2.framebufferObjectAvailable)
	{
		return;
	}

	R_BindNullFBO();

	for (i = 0; i < tr.numFBOs; i++)
	{
		fbo = tr.fbos[i];

		for (j = 0; j < glConfig2.maxColorAttachments; j++)
		{
			if (fbo->colorBuffers[j].buffer)
			{
				glDeleteRenderbuffers(1, &fbo->colorBuffers[j].buffer);
			}
		}

		if (fbo->depthBuffer.buffer)
		{
			glDeleteRenderbuffers(1, &fbo->depthBuffer.buffer);
		}

		if (fbo->stencilBuffer.buffer)
		{
			glDeleteRenderbuffers(1, &fbo->stencilBuffer.buffer);
		}

		if (fbo->frameBuffer)
		{
			glDeleteFramebuffers(1, &fbo->frameBuffer);
		}
	}
}
Example #6
0
void R_InitFBOs(void)
{
	int i;
	int width, height;

	Ren_Developer("------- R_InitFBOs -------\n");

	if (!glConfig2.framebufferObjectAvailable)
	{
		return;
	}

	R_CheckDefaultBuffer();

	tr.numFBOs = 0;

	GL_CheckErrors();

	// make sure the render thread is stopped
	R_IssuePendingRenderCommands();

	{
		// forward shading
		if (glConfig2.textureNPOTAvailable)
		{
			width  = glConfig.vidWidth;
			height = glConfig.vidHeight;
		}
		else
		{
			width  = NearestPowerOfTwo(glConfig.vidWidth);
			height = NearestPowerOfTwo(glConfig.vidHeight);
		}

		// deferredRender FBO for the HDR or LDR context
		tr.deferredRenderFBO = R_CreateFBO("_deferredRender", width, height);
		R_BindFBO(tr.deferredRenderFBO);

		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.deferredRenderFBO, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.deferredRenderFBO, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.deferredRenderFBOImage->texnum, 0);

		R_CreateFBODepthBuffer(tr.deferredRenderFBO, GL_DEPTH_COMPONENT24_ARB);
		R_AttachFBOTextureDepth(tr.depthRenderImage->texnum);

		R_CheckFBO(tr.deferredRenderFBO);
	}

	if (glConfig2.framebufferBlitAvailable)
	{
		if (glConfig2.textureNPOTAvailable)
		{
			width  = glConfig.vidWidth;
			height = glConfig.vidHeight;
		}
		else
		{
			width  = NearestPowerOfTwo(glConfig.vidWidth);
			height = NearestPowerOfTwo(glConfig.vidHeight);
		}

		tr.occlusionRenderFBO = R_CreateFBO("_occlusionRender", width, height);
		R_BindFBO(tr.occlusionRenderFBO);

#if 0
		if (glConfig2.framebufferPackedDepthStencilAvailable)
		{
			//R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA32F_ARB, 0);
			R_CreateFBOPackedDepthStencilBuffer(tr.occlusionRenderFBO, GL_DEPTH24_STENCIL8);
		}
		else
		{
			//R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_RGBA, 0);
			R_CreateFBODepthBuffer(tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24);
		}
#else
		R_CreateFBODepthBuffer(tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24);
#endif

		R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_RGBA, 0);
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.occlusionRenderFBOImage->texnum, 0);

		R_CheckFBO(tr.occlusionRenderFBO);
	}

	if (r_shadows->integer >= SHADOWING_ESM16 && glConfig2.textureFloatAvailable)
	{
		// shadowMap FBOs for shadow mapping offscreen rendering
		for (i = 0; i < MAX_SHADOWMAPS; i++)
		{
			width = height = shadowMapResolutions[i];

			tr.shadowMapFBO[i] = R_CreateFBO(va("_shadowMap%d", i), width, height);
			R_BindFBO(tr.shadowMapFBO[i]);


			if (r_shadows->integer == SHADOWING_ESM32)
			{
				R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_ALPHA32F_ARB, 0);
			}
			else if (r_shadows->integer == SHADOWING_VSM32)
			{
				R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_LUMINANCE_ALPHA32F_ARB, 0);
			}
			else if (r_shadows->integer == SHADOWING_EVSM32)
			{
				if (r_evsmPostProcess->integer)
				{
					R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_ALPHA32F_ARB, 0);
				}
				else
				{
					R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_RGBA32F_ARB, 0);
				}
			}
			else
			{
				R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_RGBA16F_ARB, 0);
			}

			R_CreateFBODepthBuffer(tr.shadowMapFBO[i], GL_DEPTH_COMPONENT24_ARB);

			R_CheckFBO(tr.shadowMapFBO[i]);
		}

		// sun requires different resolutions
		for (i = 0; i < MAX_SHADOWMAPS; i++)
		{
			width = height = sunShadowMapResolutions[i];

			tr.sunShadowMapFBO[i] = R_CreateFBO(va("_sunShadowMap%d", i), width, height);
			R_BindFBO(tr.sunShadowMapFBO[i]);

			if (r_shadows->integer == SHADOWING_ESM32)
			{
				R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_ALPHA32F_ARB, 0);
			}
			else if (r_shadows->integer == SHADOWING_VSM32)
			{
				R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_LUMINANCE_ALPHA32F_ARB, 0);
			}
			else if (r_shadows->integer == SHADOWING_EVSM32)
			{
				if (!r_evsmPostProcess->integer)
				{
					R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_RGBA32F_ARB, 0);
				}
			}
			else
			{
				R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_RGBA16F_ARB, 0);
			}

			R_CreateFBODepthBuffer(tr.sunShadowMapFBO[i], GL_DEPTH_COMPONENT24_ARB);

			if (r_shadows->integer == SHADOWING_EVSM32 && r_evsmPostProcess->integer)
			{
				R_AttachFBOTextureDepth(tr.sunShadowMapFBOImage[i]->texnum);

				/*
				Since we don't have a color attachment the framebuffer will be considered incomplete.
				Consequently, we must inform the driver that we do not wish to render to the color buffer.
				We do this with a call to set the draw-buffer and read-buffer to GL_NONE:
				*/
				glDrawBuffer(GL_NONE);
				glReadBuffer(GL_NONE);
			}

			R_CheckFBO(tr.sunShadowMapFBO[i]);
		}
	}

	{
		if (glConfig2.textureNPOTAvailable)
		{
			width  = glConfig.vidWidth;
			height = glConfig.vidHeight;
		}
		else
		{
			width  = NearestPowerOfTwo(glConfig.vidWidth);
			height = NearestPowerOfTwo(glConfig.vidHeight);
		}

		// portalRender FBO for portals, mirrors, water, cameras et cetera
		tr.portalRenderFBO = R_CreateFBO("_portalRender", width, height);
		R_BindFBO(tr.portalRenderFBO);

		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.portalRenderFBO, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.portalRenderFBO, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.portalRenderImage->texnum, 0);

		R_CheckFBO(tr.portalRenderFBO);
	}


	{
		if (glConfig2.textureNPOTAvailable)
		{
			width  = glConfig.vidWidth * 0.25f;
			height = glConfig.vidHeight * 0.25f;
		}
		else
		{
			width  = NearestPowerOfTwo(glConfig.vidWidth * 0.25f);
			height = NearestPowerOfTwo(glConfig.vidHeight * 0.25f);
		}

		tr.downScaleFBO_quarter = R_CreateFBO("_downScale_quarter", width, height);
		R_BindFBO(tr.downScaleFBO_quarter);
		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_quarter, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_quarter, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_quarter->texnum, 0);
		R_CheckFBO(tr.downScaleFBO_quarter);


		tr.downScaleFBO_64x64 = R_CreateFBO("_downScale_64x64", 64, 64);
		R_BindFBO(tr.downScaleFBO_64x64);
		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_64x64, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_64x64, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_64x64->texnum, 0);
		R_CheckFBO(tr.downScaleFBO_64x64);

#if 0
		tr.downScaleFBO_16x16 = R_CreateFBO("_downScale_16x16", 16, 16);
		R_BindFBO(tr.downScaleFBO_16x16);
		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_16x16, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_16x16, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_16x16->texnum, 0);
		R_CheckFBO(tr.downScaleFBO_16x16);


		tr.downScaleFBO_4x4 = R_CreateFBO("_downScale_4x4", 4, 4);
		R_BindFBO(tr.downScaleFBO_4x4);
		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_4x4, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_4x4, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_4x4->texnum, 0);
		R_CheckFBO(tr.downScaleFBO_4x4);


		tr.downScaleFBO_1x1 = R_CreateFBO("_downScale_1x1", 1, 1);
		R_BindFBO(tr.downScaleFBO_1x1);
		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_1x1, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_1x1, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_1x1->texnum, 0);
		R_CheckFBO(tr.downScaleFBO_1x1);
#endif

		if (glConfig2.textureNPOTAvailable)
		{
			width  = glConfig.vidWidth * 0.25f;
			height = glConfig.vidHeight * 0.25f;
		}
		else
		{
			width  = NearestPowerOfTwo(glConfig.vidWidth * 0.25f);
			height = NearestPowerOfTwo(glConfig.vidHeight * 0.25f);
		}

		tr.contrastRenderFBO = R_CreateFBO("_contrastRender", width, height);
		R_BindFBO(tr.contrastRenderFBO);

		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.contrastRenderFBO, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.contrastRenderFBO, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.contrastRenderFBOImage->texnum, 0);

		R_CheckFBO(tr.contrastRenderFBO);


		for (i = 0; i < 2; i++)
		{
			tr.bloomRenderFBO[i] = R_CreateFBO(va("_bloomRender%d", i), width, height);
			R_BindFBO(tr.bloomRenderFBO[i]);

			if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
			{
				R_CreateFBOColorBuffer(tr.bloomRenderFBO[i], GL_RGBA16F_ARB, 0);
			}
			else
			{
				R_CreateFBOColorBuffer(tr.bloomRenderFBO[i], GL_RGBA, 0);
			}
			R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.bloomRenderFBOImage[i]->texnum, 0);

			R_CheckFBO(tr.bloomRenderFBO[i]);
		}
	}

	GL_CheckErrors();

	R_BindNullFBO();
}
Example #7
0
/*
==============
R_AddAnimSurfaces
==============
*/
void R_AddAnimSurfaces(trRefEntity_t *ent)
{
	mdsHeader_t  *header = tr.currentModel->model.mds;
	mdsSurface_t *surface;
	shader_t     *shader = 0;
	int          i, fogNum, cull;
	qboolean     personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; // don't add third_person objects if not in a portal

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

	surface = ( mdsSurface_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    hash;
			int    j;

			skin = R_GetSkinByHandle(ent->e.customSkin);

			// match the surface name to something in the skin file
			shader = tr.defaultShader;

			if (ent->e.renderfx & RF_BLINK)
			{
				char *s = va("%s_b", surface->name);   // append '_b' for 'blink'
				hash = Com_HashKey(s, strlen(s));
				for (j = 0 ; j < skin->numSurfaces ; j++)
				{
					if (hash != skin->surfaces[j]->hash)
					{
						continue;
					}
					if (!strcmp(skin->surfaces[j]->name, s))
					{
						shader = skin->surfaces[j]->shader;
						break;
					}
				}
			}

			if (shader == tr.defaultShader)        // blink reference in skin was not found
			{
				hash = Com_HashKey(surface->name, sizeof(surface->name));
				for (j = 0 ; j < skin->numSurfaces ; j++)
				{
					// the names have both been lowercased
					if (hash != skin->surfaces[j]->hash)
					{
						continue;
					}
					if (!strcmp(skin->surfaces[j]->name, surface->name))
					{
						shader = skin->surfaces[j]->shader;
						break;
					}
				}
			}

			if (shader == tr.defaultShader)
			{
				Ren_Developer("WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name);
			}
			else if (shader->defaultShader)
			{
				Ren_Developer("WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
			}
		}
		else
		{
			shader = R_GetShaderByHandle(surface->shaderIndex);
		}

		// don't add third_person objects if not viewing through a portal
		if (!personalModel)
		{
			R_AddDrawSurf((void *)surface, shader, fogNum, 0, 0);
		}

		surface = ( mdsSurface_t * )((byte *)surface + surface->ofsEnd);
	}
}
Example #8
0
/*
=====================
R_AddPolysToScene
=====================
*/
static void R_AddPolysToScene(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 (!r_drawpolies->integer)
    {
        return;
    }

    if (!hShader)
    {
        Ren_Developer("WARNING: RE_AddPolyToScene: NULL poly shader\n");
        return;
    }

    for (j = 0; j < numPolys; j++)
    {
        if (r_numPolyVerts + numVerts >= r_maxpolyverts->integer || r_numPolys >= r_maxpolys->integer)
        {
            /*
               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
             */
            Ren_Developer("WARNING: RE_AddPolyToScene: r_maxPolyVerts or r_maxPolys 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));

        // 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 (BoundsIntersect(bounds[0], bounds[1], fog->bounds[0], fog->bounds[1]))
                {
                    break;
                }
            }

            if (fogIndex == tr.world->numFogs)
            {
                fogIndex = 0;
            }
        }
        poly->fogIndex = fogIndex;
    }
}
Example #9
0
/**
 * @brief Loads in a model for the given name
 * @param[in] name
 * @return 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;
	byte      *buffer;
	int       bufferLen = 0;
	int       lod;
	int       ident;
	qboolean  loaded = qfalse;
	qhandle_t hModel;
	int       numLoaded;

	if (!name || !name[0])
	{
		Ren_Developer("RE_RegisterModel: NULL name\n");
		return 0;
	}
	else
	{
		Ren_Developer("RE_RegisterModel model: %s\n", name);
	}

	if (strlen(name) >= MAX_QPATH)
	{
		Ren_Print("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)
			{
				Ren_Warning("RE_RegisterModel: bad model '%s' - already registered but in bad condition - returning 0\n", name);
				return 0;
			}
			return hModel;
		}
	}

	// allocate a new model_t
	if ((mod = R_AllocModel()) == NULL)
	{
		Ren_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));

	// make sure the render thread is stopped
	R_IssuePendingRenderCommands();

	mod->numLods = 0;

	// load the files
	numLoaded = 0;

	if (strstr(name, ".mds") || strstr(name, ".mdm") || strstr(name, ".mdx") || strstr(name, ".md5mesh") || strstr(name, ".psk"))
	{
		// try loading skeletal file

		loaded    = qfalse;
		bufferLen = ri.FS_ReadFile(name, (void **)&buffer);
		if (buffer)
		{
			ident = LittleLong(*(unsigned *)buffer);
#if 0
			if (ident == MDS_IDENT)
			{
				loaded = R_LoadMDS(mod, buffer, name);
			}
			else
#endif
			if (ident == MDM_IDENT)
			{
				loaded = R_LoadMDM(mod, buffer, name);
			}
			else if (ident == MDX_IDENT)
			{
				loaded = R_LoadMDX(mod, buffer, name);
			}

#if defined(USE_REFENTITY_ANIMATIONSYSTEM)
			if (!Q_stricmpn((const char *)buffer, "MD5Version", 10))
			{
				loaded = R_LoadMD5(mod, buffer, bufferLen, name);
			}
			else if (!Q_stricmpn((const char *)buffer, PSK_IDENTSTRING, PSK_IDENTLEN))
			{
				loaded = R_LoadPSK(mod, buffer, bufferLen, name);
			}
#endif
			ri.FS_FreeFile(buffer);
		}

		if (loaded)
		{
			// make sure the VBO glState entries are save
			R_BindNullVBO();
			R_BindNullIBO();

			return mod->index;
		}
	}

	for (lod = MD3_MAX_LODS - 1; lod >= 0; lod--)
	{
		char filename[1024];
		buffer = NULL;

		strcpy(filename, name);
		if (lod != 0)
		{
			char namebuf[80];

			if (strrchr(filename, '.'))
			{
				*strrchr(filename, '.') = 0;
			}
			sprintf(namebuf, "_%d.md3", lod);
			strcat(filename, namebuf);
		}

		filename[strlen(filename) - 1] = '3';   // try MD3 first (changed order for 2.76)
		if (ri.FS_FOpenFileRead(filename, NULL, qfalse) > 0)
		{
			ri.FS_ReadFile(filename, (void **)&buffer);
		}
		if (!buffer)
		{
			filename[strlen(filename) - 1] = 'c';   // try MDC  second
			if (ri.FS_FOpenFileRead(filename, NULL, qfalse) > 0)
			{
				ri.FS_ReadFile(filename, (void **)&buffer);
			}
			if (!buffer)
			{
				continue;
			}
		}

		ident = LittleLong(*(unsigned *)buffer);
		if (ident != MD3_IDENT && ident != MDC_IDENT)
		{
			Ren_Warning("RE_RegisterModel: unknown fileid for %s\n", name);
			ri.FS_FreeFile(buffer);
			goto fail;
		}

		if (ident == MD3_IDENT)
		{
			loaded = R_LoadMD3(mod, lod, buffer, bufferLen, name);
		}
		else if (ident == MDC_IDENT)
		{
			loaded = R_LoadMDC(mod, lod, buffer, bufferLen, name);
		}

		ri.FS_FreeFile(buffer);

		if (!loaded)
		{
			if (lod == 0)
			{
				goto fail;
			}
			else
			{
				break;
			}
		}
		else
		{
			// make sure the VBO glState entries are save
			R_BindNullVBO();
			R_BindNullIBO();

			mod->numLods++;
			numLoaded++;
			// if we have a valid model and are biased
			// so that we won't see any higher detail ones,
			// stop loading them
			//if ( lod <= r_lodbias->integer ) {
			//break;
			//}
		}
	}

	// make sure the VBO glState entries are save
	R_BindNullVBO();
	R_BindNullIBO();

	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 LEGACY_DEBUG
	else
	{
		Ren_Warning("couldn't load '%s'\n", name);
	}
#endif

fail:
	// we still keep the model_t around, so if the model name is asked for
	// again, we won't bother scanning the filesystem
	mod->type = MOD_BAD;

	// make sure the VBO glState entries are save
	R_BindNullVBO();
	R_BindNullIBO();

	return 0;
}
Example #10
0
/*
=====================
RE_AddPolysToScene
=====================
*/
void RE_AddPolysToScene(qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys)
{
	srfPoly_t *poly;
	int       i;
	int       fogIndex;
	fog_t     *fog;
	vec3_t    bounds[2];
	int       j;

	if (!tr.registered)
	{
		return;
	}

	if (!hShader)
	{
		Ren_Warning("WARNING RE_AddPolysToScene: NULL poly shader\n");
		return;
	}

	for (j = 0; j < numPolys; j++)
	{
		if (r_numpolyverts + numVerts >= r_maxpolyverts->integer)
		{
			Ren_Developer("WARNING RE_AddPolysToScene: r_maxpolyverts[%i] reached. r_numpolyverts: %i - numVerts: %i - numPolys %i - shader %i\n", r_maxpolyverts->integer, r_numpolyverts, numVerts, numPolys, hShader);
			return;
		}
		if (r_numpolys >= r_maxpolys->integer)
		{
			Ren_Developer("WARNING RE_AddPolysToScene: r_maxpolys[%i] reached. r_numpolys: %i\n", r_maxpolys->integer, r_numpolys);
			return;
		}

		poly              = &backEndData->polys[r_numpolys];
		poly->surfaceType = SF_POLY;
		poly->hShader     = hShader;
		poly->numVerts    = numVerts;
		poly->verts       = &backEndData->polyVerts[r_numpolyverts];

		memcpy(poly->verts, &verts[numVerts * j], numVerts * sizeof(*verts));

		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;
	}
}
Example #11
0
/**
 * @brief Finds and loads all .shader files, combining them into
 * a single large text block that can be scanned for shader names
 */
int ScanAndLoadShaderFilesR1()
{
	char         **shaderFiles;
	char         *buffers[MAX_SHADER_FILES];
	char         *p;
	int          numShaderFiles, i;
	char         *oldp, *token, *textEnd;
	char         **hashMem;
	int          shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash;
	unsigned int size;
	char         filename[MAX_QPATH];
	long         sum = 0, summand;

	Com_Memset(buffers, 0, MAX_SHADER_FILES);
	Com_Memset(shaderTextHashTableSizes, 0, MAX_SHADER_FILES);

	// scan for shader files
	shaderFiles = ri.FS_ListFiles("scripts", ".shader", &numShaderFiles);

	if (!shaderFiles || !numShaderFiles)
	{
		Ren_Print("----- ScanAndLoadShaderFilesR1 (no files)-----\n");
		return 0;
	}

	Ren_Print("----- ScanAndLoadShaderFilesR1 (%i files)-----\n", numShaderFiles);

	if (numShaderFiles >= MAX_SHADER_FILES)
	{
		Ren_Drop("MAX_SHADER_FILES limit is reached!");
	}

	// load and parse shader files
	for (i = 0; i < numShaderFiles; i++)
	{
		Com_sprintf(filename, sizeof(filename), "scripts/%s", shaderFiles[i]);
		COM_BeginParseSession(filename);

		Ren_Developer("...loading '%s'\n", filename);
		summand = ri.FS_ReadFile(filename, (void **)&buffers[i]);

		if (!buffers[i])
		{
			Ren_Drop("Couldn't load %s", filename); // in this case shader file is cought/listed but the file can't be read - drop!
		}

		p = buffers[i];
		while (1)
		{
			token = COM_ParseExt(&p, qtrue);

			if (!*token)
			{
				break;
			}

			// Step over the "table"/"guide" and the name
			if (!Q_stricmp(token, "table") || !Q_stricmp(token, "guide"))
			{
				token = COM_ParseExt2(&p, qtrue);

				if (!*token)
				{
					break;
				}
			}

			oldp = p;

			token = COM_ParseExt2(&p, qtrue);
			if (token[0] != '{' && token[1] != '\0')
			{
				Ren_Warning("WARNING: Bad shader file %s has incorrect syntax near token '%s' line %i\n", filename, token, COM_GetCurrentParseLine());
				ri.FS_FreeFile(buffers[i]);
				buffers[i] = NULL;
				break;
			}

			SkipBracedSection(&oldp);
			p = oldp;
		}

		if (buffers[i])
		{
			sum += summand;
		}
	}

	// build single large buffer
	s_shaderTextR1    = (char *)ri.Hunk_Alloc(sum + numShaderFiles * 2, h_low);
	s_shaderTextR1[0] = '\0';
	textEnd           = s_shaderTextR1;

	// 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_shaderTextR1);

	// free up memory
	ri.FS_FreeFileList(shaderFiles);

	Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
	size = 0;

	p = s_shaderTextR1;
	// look for shader names
	while (1)
	{
		token = COM_ParseExt(&p, qtrue);
		if (token[0] == 0)
		{
			break;
		}

		// skip shader tables
		if (!Q_stricmp(token, "table"))
		{
			// skip table name
			(void) COM_ParseExt2(&p, qtrue);

			SkipBracedSection(&p);
		}
		// support shader templates
		else if (!Q_stricmp(token, "guide"))
		{
			// parse shader name
			token = COM_ParseExt2(&p, qtrue);
			//Ren_Print("...guided '%s'\n", token);

			hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
			shaderTextHashTableSizes[hash]++;
			size++;

			// skip guide name
			token = COM_ParseExt2(&p, qtrue);

			// skip parameters
			token = COM_ParseExt2(&p, qtrue);
			if (Q_stricmp(token, "("))
			{
				Ren_Warning("expected ( found '%s'\n", token);
				break;
			}

			while (1)
			{
				token = COM_ParseExt2(&p, qtrue);

				if (!token[0])
				{
					break;
				}

				if (!Q_stricmp(token, ")"))
				{
					break;
				}
			}

			if (Q_stricmp(token, ")"))
			{
				Ren_Warning("expected ( found '%s'\n", token);
				break;
			}
		}
		else
		{
			hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
			shaderTextHashTableSizes[hash]++;
			size++;
			SkipBracedSection(&p);
		}
	}

	//Ren_Print("Shader hash table size %i\n", size);

	size += MAX_SHADERTEXT_HASH;

	hashMem = (char **)ri.Hunk_Alloc(size * sizeof(char *), h_low);

	for (i = 0; i < MAX_SHADERTEXT_HASH; i++)
	{
		shaderTextHashTableR1[i] = hashMem;
		hashMem                 += shaderTextHashTableSizes[i] + 1;
	}

	Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));

	p = s_shaderTextR1;

	// look for shader names
	while (1)
	{
		oldp  = p;
		token = COM_ParseExt(&p, qtrue);
		if (token[0] == 0)
		{
			break;
		}

		// parse shader tables
		if (!Q_stricmp(token, "table"))
		{
			int           depth;
			float         values[FUNCTABLE_SIZE];
			int           numValues;
			shaderTable_t *tb;
			qboolean      alreadyCreated;

			Com_Memset(&values, 0, sizeof(values));
			Com_Memset(&table, 0, sizeof(table));

			token = COM_ParseExt2(&p, qtrue);

			Q_strncpyz(table.name, token, sizeof(table.name));

			// check if already created
			alreadyCreated = qfalse;
			hash           = generateHashValue(table.name, MAX_SHADERTABLE_HASH);
			for (tb = shaderTableHashTable[hash]; tb; tb = tb->next)
			{
				if (Q_stricmp(tb->name, table.name) == 0)
				{
					// match found
					alreadyCreated = qtrue;
					break;
				}
			}

			depth     = 0;
			numValues = 0;
			do
			{
				token = COM_ParseExt2(&p, qtrue);

				if (!Q_stricmp(token, "snap"))
				{
					table.snap = qtrue;
				}
				else if (!Q_stricmp(token, "clamp"))
				{
					table.clamp = qtrue;
				}
				else if (token[0] == '{')
				{
					depth++;
				}
				else if (token[0] == '}')
				{
					depth--;
				}
				else if (token[0] == ',')
				{
					continue;
				}
				else
				{
					if (numValues == FUNCTABLE_SIZE)
					{
						Ren_Warning("WARNING: FUNCTABLE_SIZE hit\n");
						break;
					}
					values[numValues++] = atof(token);
				}
			}
			while (depth && p);

			if (!alreadyCreated)
			{
				Ren_Developer("...generating '%s'\n", table.name);
				GeneratePermanentShaderTable(values, numValues);
			}
		}
		// support shader templates
		else if (!Q_stricmp(token, "guide"))
		{
			// parse shader name
			oldp  = p;
			token = COM_ParseExt2(&p, qtrue);

			//Ren_Print("...guided '%s'\n", token);

			hash                                                          = generateHashValue(token, MAX_SHADERTEXT_HASH);
			shaderTextHashTableR1[hash][shaderTextHashTableSizes[hash]++] = oldp;

			// skip guide name
			token = COM_ParseExt2(&p, qtrue);

			// skip parameters
			token = COM_ParseExt2(&p, qtrue);
			if (Q_stricmp(token, "("))
			{
				Ren_Warning("expected ( found '%s'\n", token);
				break;
			}

			while (1)
			{
				token = COM_ParseExt2(&p, qtrue);

				if (!token[0])
				{
					break;
				}

				if (!Q_stricmp(token, ")"))
				{
					break;
				}
			}

			if (Q_stricmp(token, ")"))
			{
				Ren_Warning("expected ( found '%s'\n", token);
				break;
			}
		}
		else
		{
			hash                                                          = generateHashValue(token, MAX_SHADERTEXT_HASH);
			shaderTextHashTableR1[hash][shaderTextHashTableSizes[hash]++] = oldp;

			SkipBracedSection(&p);
		}
	}

	return numShaderFiles;
}
Example #12
0
/*
==============
R_AddMD5Surfaces
==============
*/
void R_AddMD5Surfaces(trRefEntity_t *ent)
{
	md5Model_t   *model = tr.currentModel->md5;
	md5Surface_t *surface;
	shader_t     *shader;
	int          i;
	qboolean     personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; // don't add third_person objects if not in a portal
	int          fogNum;

	// cull the entire model if merged bounding box of both frames
	// is outside the view frustum
	R_CullMD5(ent);
	if (ent->cull == CULL_OUT)
	{
		return;
	}

	// set up world bounds for light intersection tests
	R_SetupEntityWorldBounds(ent);

	// set up lighting now that we know we aren't culled
	if (!personalModel || r_shadows->integer > SHADOWING_BLOB)
	{
		R_SetupEntityLighting(&tr.refdef, ent, NULL);
	}

	// see if we are in a fog volume
	fogNum = R_FogWorldBox(ent->worldBounds);

	if (!r_vboModels->integer || !model->numVBOSurfaces ||
	    (!glConfig2.vboVertexSkinningAvailable && ent->e.skeleton.type == SK_ABSOLUTE))
	{
		// finally add surfaces
		for (i = 0, surface = model->surfaces; i < model->numSurfaces; i++, surface++)
		{
			if (ent->e.customShader)
			{
				shader = R_GetShaderByHandle(ent->e.customShader);
			}
			else if (ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins)
			{
				skin_t *skin;

				skin = R_GetSkinByHandle(ent->e.customSkin);

				// match the surface name to something in the skin file
				shader = tr.defaultShader;

				// FIXME: replace MD3_MAX_SURFACES for skin_t::surfaces
				if (i >= 0 && i < skin->numSurfaces && skin->surfaces[i])
				{
					shader = skin->surfaces[i]->shader;
				}
				if (shader == tr.defaultShader)
				{
					Ren_Developer("WARNING: no shader for surface %i in skin %s\n", i, skin->name);
				}
				else if (shader->defaultShader)
				{
					Ren_Developer("WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
				}
			}
			else
			{
				shader = R_GetShaderByHandle(surface->shaderIndex);
			}

			// we will add shadows even if the main object isn't visible in the view

			// don't add third_person objects if not viewing through a portal
			if (!personalModel)
			{
				R_AddDrawSurf((surfaceType_t *)surface, shader, -1, fogNum);
			}
		}
	}
	else
	{
		int             i;
		srfVBOMD5Mesh_t *vboSurface;
		shader_t        *shader;

		for (i = 0; i < model->numVBOSurfaces; i++)
		{
			vboSurface = model->vboSurfaces[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;

				skin = R_GetSkinByHandle(ent->e.customSkin);

				// match the surface name to something in the skin file
				shader = tr.defaultShader;

				// FIXME: replace MD3_MAX_SURFACES for skin_t::surfaces
				//if(i >= 0 && i < skin->numSurfaces && skin->surfaces[i])
				if (vboSurface->skinIndex >= 0 && vboSurface->skinIndex < skin->numSurfaces && skin->surfaces[vboSurface->skinIndex])
				{
					shader = skin->surfaces[vboSurface->skinIndex]->shader;
				}

				if (shader == tr.defaultShader)
				{
					Ren_Developer("WARNING: no shader for surface %i in skin %s\n", i, skin->name);
				}
				else if (shader->defaultShader)
				{
					Ren_Developer("WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
				}
			}
			else
			{
				shader = vboSurface->shader;
			}

			// don't add third_person objects if not viewing through a portal
			if (!personalModel)
			{
				R_AddDrawSurf((surfaceType_t *)vboSurface, shader, -1, fogNum);
			}
		}
	}
}
Example #13
0
/*
=================
R_AddMD5Interactions
=================
*/
void R_AddMD5Interactions(trRefEntity_t *ent, trRefLight_t *light)
{
	int               i;
	md5Model_t        *model;
	md5Surface_t      *surface;
	shader_t          *shader = 0;
	qboolean          personalModel;
	byte              cubeSideBits = CUBESIDE_CLIPALL;
	interactionType_t iaType       = IA_DEFAULT;

	// cull the entire model if merged bounding box of both frames
	// is outside the view frustum and we don't care about proper shadowing
	if (ent->cull == CULL_OUT)
	{
		if (r_shadows->integer <= SHADOWING_BLOB || light->l.noShadows)
		{
			return;
		}
		else
		{
			iaType = IA_SHADOWONLY;
		}
	}

	// avoid drawing of certain objects
#if defined(USE_REFENTITY_NOSHADOWID)
	if (light->l.inverseShadows)
	{
		if (iaType != IA_LIGHTONLY && (light->l.noShadowID && (light->l.noShadowID != ent->e.noShadowID)))
		{
			return;
		}
	}
	else
	{
		if (iaType != IA_LIGHTONLY && (light->l.noShadowID && (light->l.noShadowID == ent->e.noShadowID)))
		{
			return;
		}
	}
#endif

	// don't add third_person objects if not in a portal
	personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;

	model = tr.currentModel->md5;

	// do a quick AABB cull
	if (!BoundsIntersect(light->worldBounds[0], light->worldBounds[1], ent->worldBounds[0], ent->worldBounds[1]))
	{
		tr.pc.c_dlightSurfacesCulled += model->numSurfaces;
		return;
	}

	// do a more expensive and precise light frustum cull
	if (!r_noLightFrustums->integer)
	{
		if (R_CullLightWorldBounds(light, ent->worldBounds) == CULL_OUT)
		{
			tr.pc.c_dlightSurfacesCulled += model->numSurfaces;
			return;
		}
	}

	cubeSideBits = R_CalcLightCubeSideBits(light, ent->worldBounds);

	if (!r_vboModels->integer || !model->numVBOSurfaces ||
	    (!glConfig2.vboVertexSkinningAvailable && ent->e.skeleton.type == SK_ABSOLUTE))
	{
		// generate interactions with all surfaces
		for (i = 0, surface = model->surfaces; i < model->numSurfaces; i++, surface++)
		{
			if (ent->e.customShader)
			{
				shader = R_GetShaderByHandle(ent->e.customShader);
			}
			else if (ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins)
			{
				skin_t *skin;

				skin = R_GetSkinByHandle(ent->e.customSkin);

				// match the surface name to something in the skin file
				shader = tr.defaultShader;

				// FIXME: replace MD3_MAX_SURFACES for skin_t::surfaces
				if (i >= 0 && i < skin->numSurfaces && skin->surfaces[i])
				{
					shader = skin->surfaces[i]->shader;
				}
				if (shader == tr.defaultShader)
				{
					Ren_Developer("R_AddMD5Interactions WARNING: no shader for surface %i in skin %s\n", i, skin->name);
				}
				else if (shader->defaultShader)
				{
					Ren_Developer("R_AddMD5Interactions WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
				}
			}
			else
			{
				shader = R_GetShaderByHandle(surface->shaderIndex);
			}

			// skip all surfaces that don't matter for lighting only pass
			if (shader->isSky || (!shader->interactLight && shader->noShadows))
			{
				continue;
			}

			// we will add shadows even if the main object isn't visible in the view

			// don't add third_person objects if not viewing through a portal
			if (!personalModel)
			{
				R_AddLightInteraction(light, (surfaceType_t *)surface, shader, cubeSideBits, iaType);
				tr.pc.c_dlightSurfaces++;
			}
		}
	}
	else
	{
		int             i;
		srfVBOMD5Mesh_t *vboSurface;
		shader_t        *shader;

		for (i = 0; i < model->numVBOSurfaces; i++)
		{
			vboSurface = model->vboSurfaces[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;

				skin = R_GetSkinByHandle(ent->e.customSkin);

				// match the surface name to something in the skin file
				shader = tr.defaultShader;

				// FIXME: replace MD3_MAX_SURFACES for skin_t::surfaces
				if (i >= 0 && i < skin->numSurfaces && skin->surfaces[i])
				{
					shader = skin->surfaces[i]->shader;
				}
				if (shader == tr.defaultShader)
				{
					Ren_Developer("R_AddMD5Interactions WARNING: no shader for surface %i in skin %s\n", i, skin->name);
				}
				else if (shader->defaultShader)
				{
					Ren_Developer("R_AddMD5Interactions WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
				}
			}
			else
			{
				shader = vboSurface->shader;
			}

			// skip all surfaces that don't matter for lighting only pass
			if (shader->isSky || (!shader->interactLight && shader->noShadows))
			{
				continue;
			}

			// don't add third_person objects if not viewing through a portal
			if (!personalModel)
			{
				R_AddLightInteraction(light, (surfaceType_t *)vboSurface, shader, cubeSideBits, iaType);
				tr.pc.c_dlightSurfaces++;
			}
		}
	}
}
Example #14
0
/**
 * @brief RE_AddPolyToScene
 * @param[in] hShader
 * @param[in] numVerts
 * @param[in] verts
 */
void RE_AddPolyToScene(qhandle_t hShader, int numVerts, const polyVert_t *verts)
{
	srfPoly_t *poly;
	int       fogIndex;
	fog_t     *fog;
	vec3_t    bounds[2];

	if (!tr.registered)
	{
		return;
	}

	if (!hShader)
	{
		Ren_Warning("WARNING RE_AddPolyToScene: NULL poly shader\n");
		return;
	}

	if (((r_numpolyverts + numVerts) >= r_maxPolyVerts->integer) || (r_numpolys >= r_maxPolys->integer))
	{
		Ren_Developer("WARNING RE_AddPolyToScene: r_maxpolyverts or r_maxpolys 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 * sizeof(*verts));

	r_numpolys++;
	r_numpolyverts += numVerts;

	// see if it is in a fog volume
	if (tr.world->numfogs == 1)
	{
		fogIndex = 0;
	}
	else
	{
		int i;

		// 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;
}
Example #15
0
/**
 * @brief R_AddMDVSurfaces
 * @param[in,out] ent
 */
void R_AddMDVSurfaces(trRefEntity_t *ent)
{
	int          i;
	mdvModel_t   *model      = 0;
	mdvSurface_t *mdvSurface = 0;
	shader_t     *shader     = 0;
	int          lod;
	qboolean     personalModel;
	int          fogNum;

	// 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->mdv[0]->numFrames;
		ent->e.oldframe %= tr.currentModel->mdv[0]->numFrames;
	}

	// compute LOD
	if (ent->e.renderfx & RF_FORCENOLOD)
	{
		lod = 0;
	}
	else
	{
		lod = R_ComputeLOD(ent);
	}

	// 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[lod]->numFrames)
	    || (ent->e.frame < 0) || (ent->e.oldframe >= tr.currentModel->mdv[lod]->numFrames) || (ent->e.oldframe < 0))
	{
		//Only spam if the lod level is 0 (lods usually don't have animation frames as they are only seen from a far)
		if (lod == 0)
		{
			Ren_Developer("R_AddMDVSurfaces: no such frame %d to %d for '%s' (%d)\n",
			              ent->e.oldframe, ent->e.frame, tr.currentModel->name, tr.currentModel->mdv[lod]->numFrames);
		}
		ent->e.frame    = 0;
		ent->e.oldframe = 0;
	}

	model = tr.currentModel->mdv[lod];

	// cull the entire model if merged bounding box of both frames
	// is outside the view frustum.
	R_CullMDV(model, ent);
	if (ent->cull == CULL_OUT)
	{
		return;
	}

	// set up lighting now that we know we aren't culled
	if (!personalModel || r_shadows->integer > SHADOWING_BLOB)
	{
		R_SetupEntityLighting(&tr.refdef, ent, NULL);
	}

	// see if we are in a fog volume
	fogNum = R_FogWorldBox(ent->worldBounds);

	// draw all surfaces
	if (r_vboModels->integer && model->numVBOSurfaces)
	{
		int             i;
		srfVBOMDVMesh_t *vboSurface;
		shader_t        *shader;

		for (i = 0; i < model->numVBOSurfaces; i++)
		{
			vboSurface = model->vboSurfaces[i];
			mdvSurface = vboSurface->mdvSurface;

			shader = GetMDVSurfaceShader(ent, mdvSurface);

			// don't add third_person objects if not viewing through a portal
			if (!personalModel)
			{
				R_AddDrawSurf((surfaceType_t *)vboSurface, shader, LIGHTMAP_NONE, fogNum);
			}
		}
	}
	else
	{
		for (i = 0, mdvSurface = model->surfaces; i < model->numSurfaces; i++, mdvSurface++)
		{
			shader = GetMDVSurfaceShader(ent, mdvSurface);

			// we will add shadows even if the main object isn't visible in the view

			// don't add third_person objects if not viewing through a portal
			if (!personalModel)
			{
				R_AddDrawSurf((surfaceType_t *)mdvSurface, shader, LIGHTMAP_NONE, fogNum);
			}
		}
	}
}
Example #16
0
qboolean R_LoadPSK(model_t *mod, void *buffer, int bufferSize, const char *modName)
{
	int         i, j, k;
	memStream_t *stream = NULL;

	axChunkHeader_t chunkHeader;

	int       numPoints;
	axPoint_t *point;
	axPoint_t *points = NULL;

	int        numVertexes;
	axVertex_t *vertex;
	axVertex_t *vertexes = NULL;

	//int       numSmoothGroups;
	int          numTriangles;
	axTriangle_t *triangle;
	axTriangle_t *triangles = NULL;

	int          numMaterials;
	axMaterial_t *material;
	axMaterial_t *materials = NULL;

	int               numReferenceBones;
	axReferenceBone_t *refBone;
	axReferenceBone_t *refBones = NULL;

	int            numWeights;
	axBoneWeight_t *axWeight;
	axBoneWeight_t *axWeights = NULL;

	md5Model_t  *md5;
	md5Bone_t   *md5Bone;
	md5Weight_t *weight;

	vec3_t boneOrigin;
	quat_t boneQuat;
	//mat4_t        boneMat;

	int materialIndex, oldMaterialIndex;

	int numRemaining;

	growList_t sortedTriangles;
	growList_t vboVertexes;
	growList_t vboTriangles;
	growList_t vboSurfaces;

	int numBoneReferences;
	int boneReferences[MAX_BONES];

	mat4_t unrealToQuake;

#define DeallocAll() Com_Dealloc(materials); \
	Com_Dealloc(points); \
	Com_Dealloc(vertexes); \
	Com_Dealloc(triangles); \
	Com_Dealloc(refBones); \
	Com_Dealloc(axWeights); \
	FreeMemStream(stream);

	//MatrixSetupScale(unrealToQuake, 1, -1, 1);
	mat4_from_angles(unrealToQuake, 0, 90, 0);

	stream = AllocMemStream(buffer, bufferSize);
	GetChunkHeader(stream, &chunkHeader);

	// check indent again
	if (Q_stricmpn(chunkHeader.ident, "ACTRHEAD", 8))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "ACTRHEAD");
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	mod->type      = MOD_MD5;
	mod->dataSize += sizeof(md5Model_t);
	md5            = mod->md5 = ri.Hunk_Alloc(sizeof(md5Model_t), h_low);

	// read points
	GetChunkHeader(stream, &chunkHeader);

	if (Q_stricmpn(chunkHeader.ident, "PNTS0000", 8))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "PNTS0000");
		DeallocAll();
		return qfalse;
	}

	if (chunkHeader.dataSize != sizeof(axPoint_t))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axPoint_t));
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numPoints = chunkHeader.numData;
	points    = Com_Allocate(numPoints * sizeof(axPoint_t));

	for (i = 0, point = points; i < numPoints; i++, point++)
	{
		point->point[0] = MemStreamGetFloat(stream);
		point->point[1] = MemStreamGetFloat(stream);
		point->point[2] = MemStreamGetFloat(stream);

#if 0
		// HACK convert from Unreal coordinate system to the Quake one
		MatrixTransformPoint2(unrealToQuake, point->point);
#endif
	}

	// read vertices
	GetChunkHeader(stream, &chunkHeader);

	if (Q_stricmpn(chunkHeader.ident, "VTXW0000", 8))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "VTXW0000");
		DeallocAll();
		return qfalse;
	}

	if (chunkHeader.dataSize != sizeof(axVertex_t))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axVertex_t));
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numVertexes = chunkHeader.numData;
	vertexes    = Com_Allocate(numVertexes * sizeof(axVertex_t));

	{
		int tmpVertexInt = -1; // tmp vertex member values - MemStreamGet functions return -1 if they fail
		                       // now we print a warning if they do or abort if pointIndex is invalid

		for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++)
		{
			tmpVertexInt = MemStreamGetShort(stream);
			if (tmpVertexInt < 0 || tmpVertexInt >= numPoints)
			{
				ri.Printf(PRINT_ERROR, "R_LoadPSK: '%s' has vertex with point index out of range (%i while max %i)\n", modName, tmpVertexInt, numPoints);
				DeallocAll();
				return qfalse;
			}
			vertex->pointIndex = tmpVertexInt;

			tmpVertexInt = MemStreamGetShort(stream);
			if (tmpVertexInt < 0)
			{
				Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->unknownA)\n");
			}
			vertex->unknownA = tmpVertexInt;

			vertex->st[0] = MemStreamGetFloat(stream);
			if (vertex->st[0] == -1)
			{
				Ren_Warning("R_LoadPSK: MemStream possibly NULL or empty (vertex->st[0])\n");
			}

			vertex->st[1] = MemStreamGetFloat(stream);
			if (vertex->st[1] == -1)
			{
				Ren_Warning("R_LoadPSK: MemStream possibly NULL or empty (vertex->st[1])\n");
			}

			tmpVertexInt = MemStreamGetC(stream);
			if (tmpVertexInt < 0)
			{
				Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->materialIndex)\n");
			}
			vertex->materialIndex = tmpVertexInt;

			tmpVertexInt = MemStreamGetC(stream);
			if (tmpVertexInt < 0)
			{
				Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->materialIndex)\n");
			}
			vertex->reserved = tmpVertexInt;

			tmpVertexInt = MemStreamGetShort(stream);
			if (tmpVertexInt < 0)
			{
				Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->materialIndex)\n");
			}
			vertex->unknownB = tmpVertexInt;
#if 0
			Ren_Print("R_LoadPSK: axVertex_t(%i):\n"
			          "axVertex:pointIndex: %i\n"
			          "axVertex:unknownA: %i\n"
			          "axVertex::st: %f %f\n"
			          "axVertex:materialIndex: %i\n"
			          "axVertex:reserved: %d\n"
			          "axVertex:unknownB: %d\n",
			          i,
			          vertex->pointIndex,
			          vertex->unknownA,
			          vertex->st[0], vertex->st[1],
			          vertex->materialIndex,
			          vertex->reserved,
			          vertex->unknownB);
#endif
		}


		// read triangles
		GetChunkHeader(stream, &chunkHeader);

		if (Q_stricmpn(chunkHeader.ident, "FACE0000", 8))
		{
			Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "FACE0000");
			DeallocAll();
			return qfalse;
		}

		if (chunkHeader.dataSize != sizeof(axTriangle_t))
		{
			Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axTriangle_t));
			DeallocAll();
			return qfalse;
		}

		PrintChunkHeader(&chunkHeader);

		numTriangles = chunkHeader.numData;
		triangles    = Com_Allocate(numTriangles * sizeof(axTriangle_t));

		for (i = 0, triangle = triangles; i < numTriangles; i++, triangle++)
		{
			for (j = 0; j < 3; j++)
			//for(j = 2; j >= 0; j--)
			{
				tmpVertexInt = MemStreamGetShort(stream);

				if (tmpVertexInt < 0)
				{
					Ren_Warning("R_LoadPSK: '%s' MemStream NULL or empty (triangle->indexes[%i])\n", modName, j);
					DeallocAll();
					return qfalse;
				}

				if (tmpVertexInt >= numVertexes)
				{
					Ren_Warning("R_LoadPSK: '%s' has triangle with vertex index out of range (%i while max %i)\n", modName, tmpVertexInt, numVertexes);
					DeallocAll();
					return qfalse;
				}

				triangle->indexes[j] = tmpVertexInt;
			}

			triangle->materialIndex   = MemStreamGetC(stream);
			triangle->materialIndex2  = MemStreamGetC(stream);
			triangle->smoothingGroups = MemStreamGetLong(stream);
		}
	}
	// read materials
	GetChunkHeader(stream, &chunkHeader);

	if (Q_stricmpn(chunkHeader.ident, "MATT0000", 8))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "MATT0000");
		DeallocAll();
		return qfalse;
	}

	if (chunkHeader.dataSize != sizeof(axMaterial_t))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axMaterial_t));
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numMaterials = chunkHeader.numData;
	materials    = Com_Allocate(numMaterials * sizeof(axMaterial_t));

	for (i = 0, material = materials; i < numMaterials; i++, material++)
	{
		MemStreamRead(stream, material->name, sizeof(material->name));

		Ren_Print("R_LoadPSK: material name: '%s'\n", material->name);

		material->shaderIndex = MemStreamGetLong(stream);
		material->polyFlags   = MemStreamGetLong(stream);
		material->auxMaterial = MemStreamGetLong(stream);
		material->auxFlags    = MemStreamGetLong(stream);
		material->lodBias     = MemStreamGetLong(stream);
		material->lodStyle    = MemStreamGetLong(stream);
	}

	for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++)
	{
		if (vertex->materialIndex < 0 || vertex->materialIndex >= numMaterials)
		{
			Ren_Warning("R_LoadPSK: '%s' has vertex with material index out of range (%i while max %i)\n", modName, vertex->materialIndex, numMaterials);
			DeallocAll();
			return qfalse;
		}
	}

	for (i = 0, triangle = triangles; i < numTriangles; i++, triangle++)
	{
		if (triangle->materialIndex < 0 || triangle->materialIndex >= numMaterials)
		{
			Ren_Warning("R_LoadPSK: '%s' has triangle with material index out of range (%i while max %i)\n", modName, triangle->materialIndex, numMaterials);
			DeallocAll();
			return qfalse;
		}
	}

	// read reference bones
	GetChunkHeader(stream, &chunkHeader);

	if (Q_stricmpn(chunkHeader.ident, "REFSKELT", 8))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "REFSKELT");
		DeallocAll();
		return qfalse;
	}

	if (chunkHeader.dataSize != sizeof(axReferenceBone_t))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axReferenceBone_t));
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numReferenceBones = chunkHeader.numData;
	refBones          = Com_Allocate(numReferenceBones * sizeof(axReferenceBone_t));

	for (i = 0, refBone = refBones; i < numReferenceBones; i++, refBone++)
	{
		MemStreamRead(stream, refBone->name, sizeof(refBone->name));

		//Ren_Print("R_LoadPSK: reference bone name: '%s'\n", refBone->name);

		refBone->flags       = MemStreamGetLong(stream);
		refBone->numChildren = MemStreamGetLong(stream);
		refBone->parentIndex = MemStreamGetLong(stream);

		GetBone(stream, &refBone->bone);

#if 0
		Ren_Print("R_LoadPSK: axReferenceBone_t(%i):\n"
		          "axReferenceBone_t::name: '%s'\n"
		          "axReferenceBone_t::flags: %i\n"
		          "axReferenceBone_t::numChildren %i\n"
		          "axReferenceBone_t::parentIndex: %i\n"
		          "axReferenceBone_t::quat: %f %f %f %f\n"
		          "axReferenceBone_t::position: %f %f %f\n"
		          "axReferenceBone_t::length: %f\n"
		          "axReferenceBone_t::xSize: %f\n"
		          "axReferenceBone_t::ySize: %f\n"
		          "axReferenceBone_t::zSize: %f\n",
		          i,
		          refBone->name,
		          refBone->flags,
		          refBone->numChildren,
		          refBone->parentIndex,
		          refBone->bone.quat[0], refBone->bone.quat[1], refBone->bone.quat[2], refBone->bone.quat[3],
		          refBone->bone.position[0], refBone->bone.position[1], refBone->bone.position[2],
		          refBone->bone.length,
		          refBone->bone.xSize,
		          refBone->bone.ySize,
		          refBone->bone.zSize);
#endif
	}

	// read  bone weights
	GetChunkHeader(stream, &chunkHeader);

	if (Q_stricmpn(chunkHeader.ident, "RAWWEIGHTS", 10))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "RAWWEIGHTS");
		DeallocAll();
		return qfalse;
	}

	if (chunkHeader.dataSize != sizeof(axBoneWeight_t))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axBoneWeight_t));
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numWeights = chunkHeader.numData;
	axWeights  = Com_Allocate(numWeights * sizeof(axBoneWeight_t));

	for (i = 0, axWeight = axWeights; i < numWeights; i++, axWeight++)
	{
		axWeight->weight     = MemStreamGetFloat(stream);
		axWeight->pointIndex = MemStreamGetLong(stream);
		axWeight->boneIndex  = MemStreamGetLong(stream);

#if 0
		Ren_Print("R_LoadPSK: axBoneWeight_t(%i):\n"
		          "axBoneWeight_t::weight: %f\n"
		          "axBoneWeight_t::pointIndex %i\n"
		          "axBoneWeight_t::boneIndex: %i\n",
		          i,
		          axWeight->weight,
		          axWeight->pointIndex,
		          axWeight->boneIndex);
#endif
	}

	//
	// convert the model to an internal MD5 representation
	//
	md5->numBones = numReferenceBones;

	// calc numMeshes <number>

	/*
	numSmoothGroups = 0;
	for(i = 0, triangle = triangles; i < numTriangles; i++, triangle++)
	{
	        if(triangle->smoothingGroups)
	        {

	        }
	}
	*/

	if (md5->numBones < 1)
	{
		Ren_Warning("R_LoadPSK: '%s' has no bones\n", modName);
		DeallocAll();
		return qfalse;
	}

	if (md5->numBones > MAX_BONES)
	{
		Ren_Warning("R_LoadPSK: '%s' has more than %i bones (%i)\n", modName, MAX_BONES, md5->numBones);
		DeallocAll();
		return qfalse;
	}

	//Ren_Print("R_LoadPSK: '%s' has %i bones\n", modName, md5->numBones);

	// copy all reference bones
	md5->bones = ri.Hunk_Alloc(sizeof(*md5Bone) * md5->numBones, h_low);

	for (i = 0, md5Bone = md5->bones, refBone = refBones; i < md5->numBones; i++, md5Bone++, refBone++)
	{
		Q_strncpyz(md5Bone->name, refBone->name, sizeof(md5Bone->name));

		if (i == 0)
		{
			md5Bone->parentIndex = refBone->parentIndex - 1;
		}
		else
		{
			md5Bone->parentIndex = refBone->parentIndex;
		}

		//Ren_Print("R_LoadPSK: '%s' has bone '%s' with parent index %i\n", modName, md5Bone->name, md5Bone->parentIndex);

		if (md5Bone->parentIndex >= md5->numBones)
		{
			DeallocAll();
			Ren_Drop("R_LoadPSK: '%s' has bone '%s' with bad parent index %i while numBones is %i", modName,
			         md5Bone->name, md5Bone->parentIndex, md5->numBones);
		}

		for (j = 0; j < 3; j++)
		{
			boneOrigin[j] = refBone->bone.position[j];
		}

		// I have really no idea why the .psk format stores the first quaternion with inverted quats.
		// Furthermore only the X and Z components of the first quat are inverted ?!?!
		if (i == 0)
		{
			boneQuat[0] = refBone->bone.quat[0];
			boneQuat[1] = -refBone->bone.quat[1];
			boneQuat[2] = refBone->bone.quat[2];
			boneQuat[3] = refBone->bone.quat[3];
		}
		else
		{
			boneQuat[0] = -refBone->bone.quat[0];
			boneQuat[1] = -refBone->bone.quat[1];
			boneQuat[2] = -refBone->bone.quat[2];
			boneQuat[3] = refBone->bone.quat[3];
		}

		VectorCopy(boneOrigin, md5Bone->origin);
		//MatrixTransformPoint(unrealToQuake, boneOrigin, md5Bone->origin);

		quat_copy(boneQuat, md5Bone->rotation);

		//QuatClear(md5Bone->rotation);

#if 0
		Ren_Print("R_LoadPSK: md5Bone_t(%i):\n"
		          "md5Bone_t::name: '%s'\n"
		          "md5Bone_t::parentIndex: %i\n"
		          "md5Bone_t::quat: %f %f %f %f\n"
		          "md5bone_t::position: %f %f %f\n",
		          i,
		          md5Bone->name,
		          md5Bone->parentIndex,
		          md5Bone->rotation[0], md5Bone->rotation[1], md5Bone->rotation[2], md5Bone->rotation[3],
		          md5Bone->origin[0], md5Bone->origin[1], md5Bone->origin[2]);
#endif

		if (md5Bone->parentIndex >= 0)
		{
			vec3_t rotated;
			quat_t quat;

			md5Bone_t *parent;

			parent = &md5->bones[md5Bone->parentIndex];

			QuatTransformVector(parent->rotation, md5Bone->origin, rotated);
			//QuatTransformVector(md5Bone->rotation, md5Bone->origin, rotated);

			VectorAdd(parent->origin, rotated, md5Bone->origin);

			QuatMultiply1(parent->rotation, md5Bone->rotation, quat);
			quat_copy(quat, md5Bone->rotation);
		}

		MatrixSetupTransformFromQuat(md5Bone->inverseTransform, md5Bone->rotation, md5Bone->origin);
		mat4_inverse_self(md5Bone->inverseTransform);

#if 0
		Ren_Print("R_LoadPSK: md5Bone_t(%i):\n"
		          "md5Bone_t::name: '%s'\n"
		          "md5Bone_t::parentIndex: %i\n"
		          "md5Bone_t::quat: %f %f %f %f\n"
		          "md5bone_t::position: %f %f %f\n",
		          i,
		          md5Bone->name,
		          md5Bone->parentIndex,
		          md5Bone->rotation[0], md5Bone->rotation[1], md5Bone->rotation[2], md5Bone->rotation[3],
		          md5Bone->origin[0], md5Bone->origin[1], md5Bone->origin[2]);
#endif
	}

	Com_InitGrowList(&vboVertexes, 10000);

	for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++)
	{
		md5Vertex_t *vboVert = Com_Allocate(sizeof(*vboVert));

		for (j = 0; j < 3; j++)
		{
			vboVert->position[j] = points[vertex->pointIndex].point[j];
		}

		vboVert->texCoords[0] = vertex->st[0];
		vboVert->texCoords[1] = vertex->st[1];

		// find number of associated weights
		vboVert->numWeights = 0;

		for (j = 0, axWeight = axWeights; j < numWeights; j++, axWeight++)
		{
			if (axWeight->pointIndex == vertex->pointIndex && axWeight->weight > 0.0f)
			{
				vboVert->numWeights++;
			}
		}

		if (vboVert->numWeights > MAX_WEIGHTS)
		{
			DeallocAll();
			Ren_Drop("R_LoadPSK: vertex %i requires more weights %i than the maximum of %i in model '%s'", i, vboVert->numWeights, MAX_WEIGHTS, modName);
			//Ren_Warning( "R_LoadPSK: vertex %i requires more weights %i than the maximum of %i in model '%s'\n", i, vboVert->numWeights, MAX_WEIGHTS, modName);
		}

		vboVert->weights = ri.Hunk_Alloc(sizeof(*vboVert->weights) * vboVert->numWeights, h_low);

		for (j = 0, axWeight = axWeights, k = 0; j < numWeights; j++, axWeight++)
		{
			if (axWeight->pointIndex == vertex->pointIndex && axWeight->weight > 0.0f)
			{
				weight = ri.Hunk_Alloc(sizeof(*weight), h_low);

				weight->boneIndex  = axWeight->boneIndex;
				weight->boneWeight = axWeight->weight;

				// FIXME?
				weight->offset[0] = refBones[axWeight->boneIndex].bone.xSize;
				weight->offset[1] = refBones[axWeight->boneIndex].bone.ySize;
				weight->offset[2] = refBones[axWeight->boneIndex].bone.zSize;

				vboVert->weights[k++] = weight;
			}
		}

		Com_AddToGrowList(&vboVertexes, vboVert);
	}

	ClearBounds(md5->bounds[0], md5->bounds[1]);

	for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++)
	{
		AddPointToBounds(points[vertex->pointIndex].point, md5->bounds[0], md5->bounds[1]);
	}

#if 0
	Ren_Print("R_LoadPSK: AABB (%i %i %i) (%i %i %i)\n",
	          ( int ) md5->bounds[0][0],
	          ( int ) md5->bounds[0][1],
	          ( int ) md5->bounds[0][2],
	          ( int ) md5->bounds[1][0],
	          ( int ) md5->bounds[1][1],
	          ( int ) md5->bounds[1][2]);
#endif

	// sort triangles
	qsort(triangles, numTriangles, sizeof(axTriangle_t), CompareTrianglesByMaterialIndex);

	Com_InitGrowList(&sortedTriangles, 1000);

	for (i = 0, triangle = triangles; i < numTriangles; i++, triangle++)
	{
		skelTriangle_t *sortTri = Com_Allocate(sizeof(*sortTri));

		for (j = 0; j < 3; j++)
		{
			sortTri->indexes[j]  = triangle->indexes[j];
			sortTri->vertexes[j] = Com_GrowListElement(&vboVertexes, triangle->indexes[j]);
		}

		sortTri->referenced = qfalse;

		Com_AddToGrowList(&sortedTriangles, sortTri);
	}

	// calc tangent spaces
#if 1
	{
		md5Vertex_t *v0, *v1, *v2;
		const float *p0, *p1, *p2;
		const float *t0, *t1, *t2;
		vec3_t      tangent = { 0, 0, 0 };
		vec3_t      binormal;
		vec3_t      normal;

		for (j = 0; j < vboVertexes.currentElements; j++)
		{
			v0 = Com_GrowListElement(&vboVertexes, j);

			VectorClear(v0->tangent);
			VectorClear(v0->binormal);
			VectorClear(v0->normal);
		}

		for (j = 0; j < sortedTriangles.currentElements; j++)
		{
			skelTriangle_t *tri = Com_GrowListElement(&sortedTriangles, j);

			v0 = Com_GrowListElement(&vboVertexes, tri->indexes[0]);
			v1 = Com_GrowListElement(&vboVertexes, tri->indexes[1]);
			v2 = Com_GrowListElement(&vboVertexes, tri->indexes[2]);

			p0 = v0->position;
			p1 = v1->position;
			p2 = v2->position;

			t0 = v0->texCoords;
			t1 = v1->texCoords;
			t2 = v2->texCoords;

#if 1
			R_CalcTangentSpace(tangent, binormal, normal, p0, p1, p2, t0, t1, t2);
#else
			R_CalcNormalForTriangle(normal, p0, p1, p2);
			R_CalcTangentsForTriangle(tangent, binormal, p0, p1, p2, t0, t1, t2);
#endif

			for (k = 0; k < 3; k++)
			{
				float *v;

				v0 = Com_GrowListElement(&vboVertexes, tri->indexes[k]);

				v = v0->tangent;
				VectorAdd(v, tangent, v);

				v = v0->binormal;
				VectorAdd(v, binormal, v);

				v = v0->normal;
				VectorAdd(v, normal, v);
			}
		}

		for (j = 0; j < vboVertexes.currentElements; j++)
		{
			v0 = Com_GrowListElement(&vboVertexes, j);

			VectorNormalize(v0->tangent);
			VectorNormalize(v0->binormal);
			VectorNormalize(v0->normal);
		}
	}
#else
	{
		float       bb, s, t;
		vec3_t      bary;
		vec3_t      faceNormal;
		md5Vertex_t *dv[3];

		for (j = 0; j < sortedTriangles.currentElements; j++)
		{
			skelTriangle_t *tri = Com_GrowListElement(&sortedTriangles, j);

			dv[0] = Com_GrowListElement(&vboVertexes, tri->indexes[0]);
			dv[1] = Com_GrowListElement(&vboVertexes, tri->indexes[1]);
			dv[2] = Com_GrowListElement(&vboVertexes, tri->indexes[2]);

			R_CalcNormalForTriangle(faceNormal, dv[0]->position, dv[1]->position, dv[2]->position);

			// calculate barycentric basis for the triangle
			bb = (dv[1]->texCoords[0] - dv[0]->texCoords[0]) * (dv[2]->texCoords[1] - dv[0]->texCoords[1]) - (dv[2]->texCoords[0] - dv[0]->texCoords[0]) * (dv[1]->texCoords[1] -
			                                                                                                                                                dv[0]->texCoords[1]);

			if (fabs(bb) < 0.00000001f)
			{
				continue;
			}

			// do each vertex
			for (k = 0; k < 3; k++)
			{
				// calculate s tangent vector
				s       = dv[k]->texCoords[0] + 10.0f;
				t       = dv[k]->texCoords[1];
				bary[0] = ((dv[1]->texCoords[0] - s) * (dv[2]->texCoords[1] - t) - (dv[2]->texCoords[0] - s) * (dv[1]->texCoords[1] - t)) / bb;
				bary[1] = ((dv[2]->texCoords[0] - s) * (dv[0]->texCoords[1] - t) - (dv[0]->texCoords[0] - s) * (dv[2]->texCoords[1] - t)) / bb;
				bary[2] = ((dv[0]->texCoords[0] - s) * (dv[1]->texCoords[1] - t) - (dv[1]->texCoords[0] - s) * (dv[0]->texCoords[1] - t)) / bb;

				dv[k]->tangent[0] = bary[0] * dv[0]->position[0] + bary[1] * dv[1]->position[0] + bary[2] * dv[2]->position[0];
				dv[k]->tangent[1] = bary[0] * dv[0]->position[1] + bary[1] * dv[1]->position[1] + bary[2] * dv[2]->position[1];
				dv[k]->tangent[2] = bary[0] * dv[0]->position[2] + bary[1] * dv[1]->position[2] + bary[2] * dv[2]->position[2];

				VectorSubtract(dv[k]->tangent, dv[k]->position, dv[k]->tangent);
				VectorNormalize(dv[k]->tangent);

				// calculate t tangent vector (binormal)
				s       = dv[k]->texCoords[0];
				t       = dv[k]->texCoords[1] + 10.0f;
				bary[0] = ((dv[1]->texCoords[0] - s) * (dv[2]->texCoords[1] - t) - (dv[2]->texCoords[0] - s) * (dv[1]->texCoords[1] - t)) / bb;
				bary[1] = ((dv[2]->texCoords[0] - s) * (dv[0]->texCoords[1] - t) - (dv[0]->texCoords[0] - s) * (dv[2]->texCoords[1] - t)) / bb;
				bary[2] = ((dv[0]->texCoords[0] - s) * (dv[1]->texCoords[1] - t) - (dv[1]->texCoords[0] - s) * (dv[0]->texCoords[1] - t)) / bb;

				dv[k]->binormal[0] = bary[0] * dv[0]->position[0] + bary[1] * dv[1]->position[0] + bary[2] * dv[2]->position[0];
				dv[k]->binormal[1] = bary[0] * dv[0]->position[1] + bary[1] * dv[1]->position[1] + bary[2] * dv[2]->position[1];
				dv[k]->binormal[2] = bary[0] * dv[0]->position[2] + bary[1] * dv[1]->position[2] + bary[2] * dv[2]->position[2];

				VectorSubtract(dv[k]->binormal, dv[k]->position, dv[k]->binormal);
				VectorNormalize(dv[k]->binormal);

				// calculate the normal as cross product N=TxB
#if 0
				CrossProduct(dv[k]->tangent, dv[k]->binormal, dv[k]->normal);
				VectorNormalize(dv[k]->normal);

				// Gram-Schmidt orthogonalization process for B
				// compute the cross product B=NxT to obtain
				// an orthogonal basis
				CrossProduct(dv[k]->normal, dv[k]->tangent, dv[k]->binormal);

				if (DotProduct(dv[k]->normal, faceNormal) < 0)
				{
					VectorInverse(dv[k]->normal);
					//VectorInverse(dv[k]->tangent);
					//VectorInverse(dv[k]->binormal);
				}

#else
				VectorAdd(dv[k]->normal, faceNormal, dv[k]->normal);
#endif
			}
		}

#if 1

		for (j = 0; j < vboVertexes.currentElements; j++)
		{
			dv[0] = Com_GrowListElement(&vboVertexes, j);
			//VectorNormalize(dv[0]->tangent);
			//VectorNormalize(dv[0]->binormal);
			VectorNormalize(dv[0]->normal);
		}

#endif
	}
#endif

#if 0
	{
		md5Vertex_t *v0, *v1;

		// do another extra smoothing for normals to avoid flat shading
		for (j = 0; j < vboVertexes.currentElements; j++)
		{
			v0 = Com_GrowListElement(&vboVertexes, j);

			for (k = 0; k < vboVertexes.currentElements; k++)
			{
				if (j == k)
				{
					continue;
				}

				v1 = Com_GrowListElement(&vboVertexes, k);

				if (VectorCompare(v0->position, v1->position))
				{
					VectorAdd(v0->position, v1->normal, v0->normal);
				}
			}

			VectorNormalize(v0->normal);
		}
	}
#endif

	// split the surfaces into VBO surfaces by the maximum number of GPU vertex skinning bones
	Com_InitGrowList(&vboSurfaces, 10);

	materialIndex = oldMaterialIndex = -1;

	for (i = 0; i < numTriangles; i++)
	{
		triangle      = &triangles[i];
		materialIndex = triangle->materialIndex;

		if (materialIndex != oldMaterialIndex)
		{
			oldMaterialIndex = materialIndex;

			numRemaining = sortedTriangles.currentElements - i;

			while (numRemaining)
			{
				numBoneReferences = 0;
				Com_Memset(boneReferences, 0, sizeof(boneReferences));

				Com_InitGrowList(&vboTriangles, 1000);

				for (j = i; j < sortedTriangles.currentElements; j++)
				{
					skelTriangle_t *sortTri;

					triangle      = &triangles[j];
					materialIndex = triangle->materialIndex;

					if (materialIndex != oldMaterialIndex)
					{
						continue;
					}

					sortTri = Com_GrowListElement(&sortedTriangles, j);

					if (sortTri->referenced)
					{
						continue;
					}

					if (AddTriangleToVBOTriangleList(&vboTriangles, sortTri, &numBoneReferences, boneReferences))
					{
						sortTri->referenced = qtrue;
					}
				}

				for (j = 0; j < MAX_BONES; j++)
				{
					if (boneReferences[j] > 0)
					{
						Ren_Print("R_LoadPSK: referenced bone: '%s'\n", (j < numReferenceBones) ? refBones[j].name : NULL);
					}
				}

				if (!vboTriangles.currentElements)
				{
					Ren_Warning("R_LoadPSK: could not add triangles to a remaining VBO surface for model '%s'\n", modName);
					break;
				}

				// FIXME skinIndex
				AddSurfaceToVBOSurfacesList2(&vboSurfaces, &vboTriangles, &vboVertexes, md5, vboSurfaces.currentElements, materials[oldMaterialIndex].name, numBoneReferences, boneReferences);
				numRemaining -= vboTriangles.currentElements;

				Com_DestroyGrowList(&vboTriangles);
			}
		}
	}

	for (j = 0; j < sortedTriangles.currentElements; j++)
	{
		skelTriangle_t *sortTri = Com_GrowListElement(&sortedTriangles, j);
		Com_Dealloc(sortTri);
	}

	Com_DestroyGrowList(&sortedTriangles);

	for (j = 0; j < vboVertexes.currentElements; j++)
	{
		md5Vertex_t *v = Com_GrowListElement(&vboVertexes, j);
		Com_Dealloc(v);
	}

	Com_DestroyGrowList(&vboVertexes);

	// move VBO surfaces list to hunk
	md5->numVBOSurfaces = vboSurfaces.currentElements;
	md5->vboSurfaces    = ri.Hunk_Alloc(md5->numVBOSurfaces * sizeof(*md5->vboSurfaces), h_low);

	for (i = 0; i < md5->numVBOSurfaces; i++)
	{
		md5->vboSurfaces[i] = ( srfVBOMD5Mesh_t * ) Com_GrowListElement(&vboSurfaces, i);
	}

	Com_DestroyGrowList(&vboSurfaces);

	FreeMemStream(stream);
	Com_Dealloc(points);
	Com_Dealloc(vertexes);
	Com_Dealloc(triangles);
	Com_Dealloc(materials);

	Ren_Developer("%i VBO surfaces created for PSK model '%s'\n", md5->numVBOSurfaces, modName);

	return qtrue;
}
Example #17
0
/**
 * @brief Creates a new decal projector from a triangle.
 *
 * Projected polygons should be 3 or 4 points.
 *
 * If a single point is passed in (numPoints == 1) then the decal will be omnidirectional
 * omnidirectional decals use points[ 0 ] as center and projection[ 3 ] as radius
 * pass in lifeTime < 0 for a temporary mark.
 *
 * @param[in] hShader
 * @param[in] numPoints
 * @param[in] points
 * @param[in] projection
 * @param[in] color
 * @param[in] lifeTime
 * @param[in] fadeTime
 */
void RE_ProjectDecal(qhandle_t hShader, int numPoints, vec3_t *points, vec4_t projection, vec4_t color, int lifeTime,
                     int fadeTime)
{
	static int       totalProjectors = 0;
	vec3_t           xyz;
	decalVert_t      dv[4];
	int              i;
	decalProjector_t *dp, temp;

	if (r_numDecalProjectors >= MAX_DECAL_PROJECTORS)
	{
		Ren_Print("WARNING: RE_ProjectDecal() Max decal projectors reached (%d)\n", MAX_DECAL_PROJECTORS);
		return;
	}

	// dummy check
	if (numPoints != 1 && numPoints != 3 && numPoints != 4)
	{
		Ren_Print("WARNING: RE_ProjectDecal() Invalid number of decal points (%d)\n", numPoints);
		return;
	}

	// early outs
	if (lifeTime == 0)
	{
		Ren_Developer("WARNING: RE_ProjectDecal() lifeTime == 0\n"); // modders should have a look at this - vanilla does these calls
		return;
	}
	if (projection[3] <= 0.0f)
	{
		Ren_Print("WARNING: RE_ProjectDecal() projection[3] <= 0.0f\n");
		return;
	}

	// set times properly
	if (lifeTime < 0 || fadeTime < 0)
	{
		lifeTime = 0;
		fadeTime = 0;
	}

	// basic setup
	temp.shader        = R_GetShaderByHandle(hShader);
	temp.color[0]      = (byte)(color[0] * 255);
	temp.color[1]      = (byte)(color[1] * 255);
	temp.color[2]      = (byte)(color[2] * 255);
	temp.color[3]      = (byte)(color[3] * 255);
	temp.numPlanes     = numPoints + 2;
	temp.fadeStartTime = tr.refdef.time + lifeTime - fadeTime; // FIXME: stale refdef time
	temp.fadeEndTime   = temp.fadeStartTime + fadeTime;
	temp.projectorNum  = 0;

	// set up decal texcoords (FIXME: support arbitrary projector st coordinates in trapcall)
	dv[0].st[0] = 0.0f;
	dv[0].st[1] = 0.0f;
	dv[1].st[0] = 0.0f;
	dv[1].st[1] = 1.0f;
	dv[2].st[0] = 1.0f;
	dv[2].st[1] = 1.0f;
	dv[3].st[0] = 1.0f;
	dv[3].st[1] = 0.0f;

	// omnidirectional?
	if (numPoints == 1)
	{
		float radius;
		float iDist;

		// set up omnidirectional
		numPoints            = 4;
		temp.numPlanes       = 6;
		temp.omnidirectional = qtrue;
		radius               = projection[3];

		Vector4Set(projection, 0.0f, 0.0f, -1.0f, radius * 2.0f);
		iDist = 1.0f / (radius * 2.0f);

		// set corner
		VectorSet(xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius);

		// make x axis texture matrix (yz)
		VectorSet(temp.texMat[0][0], 0.0f, iDist, 0.0f);
		temp.texMat[0][0][3] = -DotProduct(temp.texMat[0][0], xyz);
		VectorSet(temp.texMat[0][1], 0.0f, 0.0f, iDist);
		temp.texMat[0][1][3] = -DotProduct(temp.texMat[0][1], xyz);

		// make y axis texture matrix (xz)
		VectorSet(temp.texMat[1][0], iDist, 0.0f, 0.0f);
		temp.texMat[1][0][3] = -DotProduct(temp.texMat[1][0], xyz);
		VectorSet(temp.texMat[1][1], 0.0f, 0.0f, iDist);
		temp.texMat[1][1][3] = -DotProduct(temp.texMat[1][1], xyz);

		// make z axis texture matrix (xy)
		VectorSet(temp.texMat[2][0], iDist, 0.0f, 0.0f);
		temp.texMat[2][0][3] = -DotProduct(temp.texMat[2][0], xyz);
		VectorSet(temp.texMat[2][1], 0.0f, iDist, 0.0f);
		temp.texMat[2][1][3] = -DotProduct(temp.texMat[2][1], xyz);

		// setup decal points
		VectorSet(dv[0].xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius);
		VectorSet(dv[1].xyz, points[0][0] - radius, points[0][1] + radius, points[0][2] + radius);
		VectorSet(dv[2].xyz, points[0][0] + radius, points[0][1] + radius, points[0][2] + radius);
		VectorSet(dv[3].xyz, points[0][0] + radius, points[0][1] - radius, points[0][2] + radius);
	}
	else
	{
		// set up unidirectional
		temp.omnidirectional = qfalse;

		// set up decal points
		VectorCopy(points[0], dv[0].xyz);
		VectorCopy(points[1], dv[1].xyz);
		VectorCopy(points[2], dv[2].xyz);
		VectorCopy(points[3], dv[3].xyz);

		// make texture matrix
		if (!MakeTextureMatrix(temp.texMat[0], projection, &dv[0], &dv[1], &dv[2]))
		{
			Ren_Print("WARNING: RE_ProjectDecal() MakeTextureMatrix returns NULL\n");
			return;
		}
	}

	// bound the projector
	ClearBounds(temp.mins, temp.maxs);
	for (i = 0; i < numPoints; i++)
	{
		AddPointToBounds(dv[i].xyz, temp.mins, temp.maxs);
		VectorMA(dv[i].xyz, projection[3], projection, xyz);
		AddPointToBounds(xyz, temp.mins, temp.maxs);
	}

	// make bounding sphere
	VectorAdd(temp.mins, temp.maxs, temp.center);
	VectorScale(temp.center, 0.5f, temp.center);
	VectorSubtract(temp.maxs, temp.center, xyz);
	temp.radius  = VectorLength(xyz);
	temp.radius2 = temp.radius * temp.radius;

	// make the front plane
	if (!PlaneFromPoints(temp.planes[0], dv[0].xyz, dv[1].xyz, dv[2].xyz))
	{
		Ren_Developer("WARNING: RE_ProjectDecal() PlaneFromPoints is NULL\n"); // occurs on UJE_fueldump
		return;
	}

	// make the back plane
	VectorSubtract(vec3_origin, temp.planes[0], temp.planes[1]);
	VectorMA(dv[0].xyz, projection[3], projection, xyz);
	temp.planes[1][3] = DotProduct(xyz, temp.planes[1]);

	// make the side planes
	for (i = 0; i < numPoints; i++)
	{
		VectorMA(dv[i].xyz, projection[3], projection, xyz);
		if (!PlaneFromPoints(temp.planes[i + 2], dv[(i + 1) % numPoints].xyz, dv[i].xyz, xyz))
		{
			Ren_Developer("WARNING: RE_ProjectDecal() a side plane is NULL\n"); // occurs on map venice
			return;
		}
	}

	// create a new projector
	dp = &backEndData->decalProjectors[r_numDecalProjectors];
	Com_Memcpy(dp, &temp, sizeof(*dp));
	dp->projectorNum = totalProjectors++;

	// we have a winner
	r_numDecalProjectors++;
}
Example #18
0
/**
 * @brief Logs OpenGL commands when com_developer cvar is enabled
 */
void GLimp_LogComment(const char *comment)
{
	Ren_Developer("%s", comment);
}
Example #19
0
static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder)
{
	int             perChannelColorBits;
	int             colorBits, depthBits, stencilBits;
	int             samples;
	int             i     = 0;
	SDL_Surface     *icon = NULL;
	SDL_DisplayMode desktopMode;
	int             display = 0;
	int             x       = SDL_WINDOWPOS_UNDEFINED, y = SDL_WINDOWPOS_UNDEFINED;

	Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_GRABBED;

#ifndef FEATURE_RENDERER_GLES
	GLenum glewResult;
#endif

	Ren_Print("Initializing OpenGL display\n");

	if (r_allowResize->integer && !fullscreen)
	{
		flags |= SDL_WINDOW_RESIZABLE;
	}

	icon = SDL_CreateRGBSurfaceFrom(
	    (void *)CLIENT_WINDOW_ICON.pixel_data,
	    CLIENT_WINDOW_ICON.width,
	    CLIENT_WINDOW_ICON.height,
	    CLIENT_WINDOW_ICON.bytes_per_pixel * 8,
	    CLIENT_WINDOW_ICON.bytes_per_pixel * CLIENT_WINDOW_ICON.width,
#ifdef Q3_LITTLE_ENDIAN
	    0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
#else
	    0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
#endif
	    );

	// If a window exists, note its display index
	if (main_window != NULL)
	{
		display = SDL_GetWindowDisplayIndex(main_window);
	}

	if (SDL_GetDesktopDisplayMode(display, &desktopMode) == 0)
	{
		displayAspect = (float)desktopMode.w / (float)desktopMode.h;

		Ren_Print("Estimated display aspect: %.3f\n", displayAspect);
	}
	else
	{
		Com_Memset(&desktopMode, 0, sizeof(SDL_DisplayMode));

		Ren_Print("Cannot estimate display aspect, assuming 1.333\n");
	}

	Ren_Print("...setting mode %d: ", mode);

	if (mode == -2)
	{
		// use desktop video resolution
		if (desktopMode.h > 0)
		{
			glConfig.vidWidth  = desktopMode.w;
			glConfig.vidHeight = desktopMode.h;
		}
		else
		{
			glConfig.vidWidth  = 640;
			glConfig.vidHeight = 480;
			Ren_Print("Cannot determine display resolution, assuming 640x480\n");
		}

		glConfig.windowAspect = (float)glConfig.vidWidth / (float)glConfig.vidHeight;
	}
	else if (!R_GetModeInfo(&glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode))
	{
		Ren_Print("invalid mode\n");
		return RSERR_INVALID_MODE;
	}
	Ren_Print("%dx%d\n", glConfig.vidWidth, glConfig.vidHeight);

	// Center window
	if (r_centerWindow->integer && !fullscreen)
	{
		x = (desktopMode.w / 2) - (glConfig.vidWidth / 2);
		y = (desktopMode.h / 2) - (glConfig.vidHeight / 2);
	}

	// Destroy existing state if it exists
	if (SDL_glContext != NULL)
	{
		SDL_GL_DeleteContext(SDL_glContext);
		SDL_glContext = NULL;
	}

	if (main_window != NULL)
	{
		SDL_GetWindowPosition(main_window, &x, &y);
		Ren_Developer("Existing window at %dx%d before being destroyed\n", x, y);
		SDL_DestroyWindow(main_window);
		main_window = NULL;
	}

	if (fullscreen)
	{
		if (r_mode->integer == -2)
		{
			flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
		}
		else
		{
			flags |= SDL_WINDOW_FULLSCREEN;
		}

		glConfig.isFullscreen = qtrue;
	}
	else
	{
		if (noborder)
		{
			flags |= SDL_WINDOW_BORDERLESS;
		}

		glConfig.isFullscreen = qfalse;
	}

	colorBits = r_colorbits->value;
	if ((!colorBits) || (colorBits >= 32))
	{
		colorBits = 24;
	}

	if (!r_depthbits->value)
	{
		depthBits = 24;
	}
	else
	{
		depthBits = r_depthbits->value;
	}
	stencilBits = r_stencilbits->value;
	samples     = r_ext_multisample->value;

	for (i = 0; i < 16; i++)
	{
		int testColorBits, testDepthBits, testStencilBits;

		// 0 - default
		// 1 - minus colorBits
		// 2 - minus depthBits
		// 3 - minus stencil
		if ((i % 4) == 0 && i)
		{
			// one pass, reduce
			switch (i / 4)
			{
			case 2:
				if (colorBits == 24)
				{
					colorBits = 16;
				}
				break;
			case 1:
				if (depthBits == 32)
				{
					depthBits = 24;
				}
				else if (depthBits == 24)
				{
					depthBits = 16;
				}
				else if (depthBits == 16)
				{
					depthBits = 8;
				}
			case 3: // fall through
				if (stencilBits == 24)
				{
					stencilBits = 16;
				}
				else if (stencilBits == 16)
				{
					stencilBits = 8;
				}
			}
		}

		testColorBits   = colorBits;
		testDepthBits   = depthBits;
		testStencilBits = stencilBits;

		if ((i % 4) == 3) // reduce colorbits
		{
			if (testColorBits == 24)
			{
				testColorBits = 16;
			}
		}

		if ((i % 4) == 2) // reduce depthbits
		{
			if (testDepthBits == 24)
			{
				testDepthBits = 16;
			}
			else if (testDepthBits == 16)
			{
				testDepthBits = 8;
			}
		}

		if ((i % 4) == 1) // reduce stencilbits
		{
			if (testStencilBits == 24)
			{
				testStencilBits = 16;
			}
			else if (testStencilBits == 16)
			{
				testStencilBits = 8;
			}
			else
			{
				testStencilBits = 0;
			}
		}

		if (testColorBits == 24)
		{
			perChannelColorBits = 8;
		}
		else
		{
			perChannelColorBits = 4;
		}

#ifdef __sgi // Fix for SGIs grabbing too many bits of color
		if (perChannelColorBits == 4)
		{
			perChannelColorBits = 0; /* Use minimum size for 16-bit color */

		}
		// Need alpha or else SGIs choose 36+ bit RGB mode
		SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 1);
#endif

		SDL_GL_SetAttribute(SDL_GL_RED_SIZE, perChannelColorBits);
		SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, perChannelColorBits);
		SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, perChannelColorBits);
		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, testDepthBits);
		SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, testStencilBits);

		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0);
		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, samples);

		// SDL2 uses opengl by default, if we want opengl es we need to set this attribute
		//SDL_GL_SetAttribute(SDL_GL_CONTEXT_EGL, 1);

		if (r_stereoEnabled->integer)
		{
			glConfig.stereoEnabled = qtrue;
			SDL_GL_SetAttribute(SDL_GL_STEREO, 1);
		}
		else
		{
			glConfig.stereoEnabled = qfalse;
			SDL_GL_SetAttribute(SDL_GL_STEREO, 0);
		}

		SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

		// If not allowing software GL, demand accelerated
		if (!r_allowSoftwareGL->integer)
		{
			SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
		}

		main_window = SDL_CreateWindow(CLIENT_WINDOW_TITLE, x, y, glConfig.vidWidth, glConfig.vidHeight, flags | SDL_WINDOW_SHOWN);

		if (!main_window)
		{
			Ren_Developer("SDL_CreateWindow failed: %s\n", SDL_GetError());
			continue;
		}

		//This is disabled since at least now we have no use for this
		/*
		if (!Glimp_Create2DRenderer(main_window))
		{
		    continue;
		}
		*/

		if (fullscreen)
		{
			SDL_DisplayMode mode;

			switch (testColorBits)
			{
			case 16: mode.format = SDL_PIXELFORMAT_RGB565; break;
			case 24: mode.format = SDL_PIXELFORMAT_RGB24;  break;
			default: Ren_Developer("testColorBits is %d, can't fullscreen\n", testColorBits); continue;
			}

			mode.w            = glConfig.vidWidth;
			mode.h            = glConfig.vidHeight;
			mode.refresh_rate = glConfig.displayFrequency = ri.Cvar_VariableIntegerValue("r_displayRefresh");
			mode.driverdata   = NULL;

			if (SDL_SetWindowDisplayMode(main_window, &mode) < 0)
			{
				Ren_Developer("SDL_SetWindowDisplayMode failed: %s\n", SDL_GetError());
				continue;
			}
		}

		SDL_SetWindowIcon(main_window, icon);

#if defined(FEATURE_RENDERER2)
		glewExperimental = GL_TRUE;

		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
#endif

		if ((SDL_glContext = SDL_GL_CreateContext(main_window)) == NULL)
		{
			Ren_Developer("SDL_GL_CreateContext failed: %s\n", SDL_GetError());
			continue;
		}

		SDL_GL_MakeCurrent(main_window, SDL_glContext);
		SDL_GL_SetSwapInterval(r_swapInterval->integer);

		glConfig.colorBits   = testColorBits;
		glConfig.depthBits   = testDepthBits;
		glConfig.stencilBits = testStencilBits;

		ri.Printf(PRINT_ALL, "Using %d color bits, %d depth, %d stencil display.\n",
		          glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits);
		break;
	}

	GLimp_DetectAvailableModes();

#if !defined(FEATURE_RENDERER_GLES)
	glewResult = glewInit();

	if (GLEW_OK != glewResult)
	{
		// glewInit failed, something is seriously wrong
		Ren_Fatal("GLW_StartOpenGL() - could not load OpenGL subsystem: %s", glewGetErrorString(glewResult));
	}
	else
	{
		Ren_Print("Using GLEW %s\n", glewGetString(GLEW_VERSION));
	}
#endif

	if (!GLimp_InitOpenGLContext())
	{
		return RSERR_OLD_GL;
	}

	if (!main_window) //|| !main_renderer)
	{
		Ren_Print("Couldn't get a visual\n");
		return RSERR_INVALID_MODE;
	}

	SDL_FreeSurface(icon);

	return RSERR_OK;
}
Example #20
0
/*
=================
R_AddMDCSurfaces
=================
*/
void R_AddMDCSurfaces(trRefEntity_t *ent)
{
	int          i;
	mdcHeader_t  *header    = 0;
	mdcSurface_t *surface   = 0;
	md3Shader_t  *md3Shader = 0;
	shader_t     *shader    = 0;
	int          cull;
	int          lod;
	int          fogNum;
	qboolean     personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; // don't add third_person objects if not in a portal

	if (ent->e.renderfx & RF_WRAP_FRAMES)
	{
		ent->e.frame    %= tr.currentModel->model.mdc[0]->numFrames;
		ent->e.oldframe %= tr.currentModel->model.mdc[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->model.mdc[0]->numFrames)
	    || (ent->e.frame < 0)
	    || (ent->e.oldframe >= tr.currentModel->model.mdc[0]->numFrames)
	    || (ent->e.oldframe < 0))
	{
		Ren_Developer("R_AddMDCSurfaces: 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
	if (ent->e.renderfx & RF_FORCENOLOD)
	{
		lod = 0;
	}
	else
	{
		lod = R_ComputeLOD(ent);
	}

	header = tr.currentModel->model.mdc[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 = ( mdcSurface_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    hash;
			int    j;

			skin = R_GetSkinByHandle(ent->e.customSkin);

			// match the surface name to something in the skin file
			shader = tr.defaultShader;
			// added blink
			if (ent->e.renderfx & RF_BLINK)
			{
				char *s = va("%s_b", surface->name);   // append '_b' for 'blink'

				hash = Com_HashKey(s, strlen(s));
				for (j = 0 ; j < skin->numSurfaces ; j++)
				{
					if (hash != skin->surfaces[j]->hash)
					{
						continue;
					}
					if (!strcmp(skin->surfaces[j]->name, s))
					{
						shader = skin->surfaces[j]->shader;
						break;
					}
				}
			}

			if (shader == tr.defaultShader)        // blink reference in skin was not found
			{
				hash = Com_HashKey(surface->name, sizeof(surface->name));
				for (j = 0 ; j < skin->numSurfaces ; j++)
				{
					// the names have both been lowercased
					if (hash != skin->surfaces[j]->hash)
					{
						continue;
					}
					if (!strcmp(skin->surfaces[j]->name, surface->name))
					{
						shader = skin->surfaces[j]->shader;
						break;
					}
				}
			}
		}
		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, 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);
		}

		// for testing polygon shadows (on /all/ models)
		if (r_shadows->integer == 4)
		{
			R_AddDrawSurf((void *)surface, tr.projectionShadowShader, 0, 0, 0);
		}

		// don't add third_person objects if not viewing through a portal
		if (!personalModel)
		{
			R_AddDrawSurf((void *)surface, shader, fogNum, 0, 0);
		}

		surface = ( mdcSurface_t * )((byte *)surface + surface->ofsEnd);
	}
}