Beispiel #1
0
/*
=============
Q_strreplace

replaces content of find by replace in dest
=============
*/
qboolean Q_strreplace(char *dest, int destsize, const char *find, const char *replace)
{
	int  lend;
	char *s;
	char backup[32000];             // big, but small enough to fit in PPC stack

	lend = strlen(dest);
	if (lend >= destsize)
	{
		Ren_Fatal("Q_strreplace: already overflowed");
	}

	s = strstr(dest, find);
	if (!s)
	{
		return qfalse;
	}
	else
	{
		int lstart, lfind, lreplace;

		Q_strncpyz(backup, dest, lend + 1);
		lstart   = s - dest;
		lfind    = strlen(find);
		lreplace = strlen(replace);

		strncpy(s, replace, destsize - lstart - 1);
		strncpy(s + lreplace, backup + lstart + lfind, destsize - lstart - lreplace - 1);

		return qtrue;
	}
}
Beispiel #2
0
void R_CopyToFBO(FBO_t *from, FBO_t *to, GLuint mask, GLuint filter)
{
	if (glConfig2.framebufferBlitAvailable)
	{
		vec2_t size;
		if (from)
		{
			glBindFramebuffer(GL_READ_FRAMEBUFFER, from->frameBuffer);
			size[0] = from->width;
			size[1] = from->height;
		}
		else
		{
			glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
			size[0] = glConfig.vidWidth;
			size[1] = glConfig.vidHeight;
		}

		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, to->frameBuffer);
		glBlitFramebuffer(0, 0, size[0], size[1], 0, 0, to->width, to->height, mask, filter);

		//Just set the read buffer to the target as well otherwise we might get f****d..
		glBindFramebuffer(GL_FRAMEBUFFER, to->frameBuffer);
		glState.currentFBO = to;
	}
	else
	{
		// FIXME add non EXT_framebuffer_blit code
		Ren_Fatal("R_CopyToFBO no framebufferblitting available");
	}
}
Beispiel #3
0
int RE_InitOpenGlSubsystems(void)
{
#ifndef FEATURE_RENDERER_GLES
	GLenum glewResult;
#endif

#if !defined(FEATURE_RENDERER_GLES)

#if defined(FEATURE_RENDERER2)
	glewExperimental = GL_TRUE;
#endif

	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
	{
		Com_Printf("Using GLEW %s\n", glewGetString(GLEW_VERSION));
	}
#endif

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

	return qtrue;
}
Beispiel #4
0
static boolean empty_output_buffer(j_compress_ptr cinfo)
{
	my_dest_ptr dest = ( my_dest_ptr ) cinfo->dest;

	jpeg_destroy_compress(cinfo);

	// Make crash fatal or we would probably leak memory.
	Ren_Fatal("Output buffer for encoded JPEG image has insufficient size of %d bytes",
	          dest->size);

	return FALSE;
}
Beispiel #5
0
static void R_CheckDefaultBuffer()
{
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glBindRenderbuffer(GL_RENDERBUFFER, 0);
	glState.currentFBO = NULL;

	{
		unsigned int fbostatus = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
		if (fbostatus != GL_FRAMEBUFFER_COMPLETE)
		{
			if (fbostatus == GL_FRAMEBUFFER_UNDEFINED)
			{
				Ren_Fatal("Default framebuffer is undefined!");
			}
			else
			{
				Ren_Fatal("There is an issue with the opengl context:s default framebuffer...%i", fbostatus);
			}
		}
	}
}
Beispiel #6
0
/*
============
R_CreateIBO
============
*/
IBO_t *R_CreateIBO(const char *name, byte *indexes, int indexesSize, vboUsage_t usage)
{
	IBO_t *ibo;
	int   glUsage;

	switch (usage)
	{
	case VBO_USAGE_STATIC:
		glUsage = GL_STATIC_DRAW;
		break;
	case VBO_USAGE_DYNAMIC:
		glUsage = GL_DYNAMIC_DRAW;
		break;
	default:
		glUsage = 0;
		Ren_Fatal("bad vboUsage_t given: %i", usage);
		break;
	}

	if (strlen(name) >= MAX_QPATH)
	{
		Ren_Drop("R_CreateIBO: \"%s\" is too long\n", name);
	}

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

	ibo = (IBO_t *)ri.Hunk_Alloc(sizeof(*ibo), h_low);
	Com_AddToGrowList(&tr.ibos, ibo);

	Q_strncpyz(ibo->name, name, sizeof(ibo->name));

	ibo->indexesSize = indexesSize;

	glGenBuffers(1, &ibo->indexesVBO);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->indexesVBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexesSize, indexes, glUsage);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	GL_CheckErrors();

	return ibo;
}
Beispiel #7
0
static void R_InitUnitCubeVBO()
{
	vec3_t        mins = { -1, -1, -1 };
	vec3_t        maxs = { 1, 1, 1 };
	int           i;
	srfVert_t     *verts;
	srfTriangle_t *triangles;

	if (glConfig.smpActive)
	{
		Ren_Fatal("R_InitUnitCubeVBO: FIXME SMP");
	}

	tess.multiDrawPrimitives = 0;
	tess.numIndexes          = 0;
	tess.numVertexes         = 0;

	Tess_AddCube(vec3_origin, mins, maxs, colorWhite);

	verts     = (srfVert_t *)ri.Hunk_AllocateTempMemory(tess.numVertexes * sizeof(srfVert_t));
	triangles = (srfTriangle_t *)ri.Hunk_AllocateTempMemory((tess.numIndexes / 3) * sizeof(srfTriangle_t));

	for (i = 0; i < tess.numVertexes; i++)
	{
		VectorCopy(tess.xyz[i], verts[i].xyz);
	}

	for (i = 0; i < (tess.numIndexes / 3); i++)
	{
		triangles[i].indexes[0] = tess.indexes[i * 3 + 0];
		triangles[i].indexes[1] = tess.indexes[i * 3 + 1];
		triangles[i].indexes[2] = tess.indexes[i * 3 + 2];
	}

	tr.unitCubeVBO = R_CreateVBO2("unitCube_VBO", tess.numVertexes, verts, ATTR_POSITION, VBO_USAGE_STATIC);
	tr.unitCubeIBO = R_CreateIBO2("unitCube_IBO", tess.numIndexes / 3, triangles, VBO_USAGE_STATIC);

	ri.Hunk_FreeTempMemory(triangles);
	ri.Hunk_FreeTempMemory(verts);

	tess.multiDrawPrimitives = 0;
	tess.numIndexes          = 0;
	tess.numVertexes         = 0;
}
Beispiel #8
0
int Com_AddToGrowList(growList_t *list, void *data)
{
	void **old;

	if (list->currentElements != list->maxElements)
	{
		list->elements[list->currentElements] = data;
		return list->currentElements++;
	}

	// grow, reallocate and move
	old = list->elements;

	if (list->maxElements < 0)
	{
		Ren_Fatal("Com_AddToGrowList: maxElements = %i", list->maxElements);
	}

	if (list->maxElements == 0)
	{
		// initialize the list to hold 100 elements
		Com_InitGrowList(list, 100);
		return Com_AddToGrowList(list, data);
	}

	list->maxElements *= 2;

	//Com_DPrintf("Resizing growlist to %i maxElements\n", list->maxElements);

	list->elements = (void **)Com_Allocate(list->maxElements * sizeof(void *));

	if (!list->elements)
	{
		Ren_Drop("Growlist alloc failed");
	}

	Com_Memcpy(list->elements, old, list->currentElements * sizeof(void *));

	Com_Dealloc(old);

	return Com_AddToGrowList(list, data);
}
Beispiel #9
0
/**
 * @brief Make sure there is enough command space, waiting on the
 * render thread if needed.
 * @param[in] bytes
 * @return
 */
void *R_GetCommandBuffer(unsigned int bytes)
{
	renderCommandList_t *cmdList = &backEndData->commands;

	// always leave room for the swap buffers and end of list commands
	// - added swapBuffers_t from ET
	if (cmdList->used + bytes + (sizeof(swapBuffersCommand_t) + sizeof(int)) > MAX_RENDER_COMMANDS)
	{
		if (bytes > MAX_RENDER_COMMANDS - (sizeof(swapBuffersCommand_t) + sizeof(int)))
		{
			Ren_Fatal("R_GetCommandBuffer: bad size %u", bytes);
		}
		// if we run out of room, just start dropping commands
		return NULL;
	}

	cmdList->used += bytes;

	return cmdList->cmds + cmdList->used - bytes;
}
Beispiel #10
0
static qboolean GLimp_CheckForVersionExtension(const char *ext, int coresince, qboolean required, cvar_t *var)
{
	qboolean result = qfalse;

	if ((coresince >= 0 && coresince <= glConfig2.contextCombined) || GL_CheckForExtension(ext))
	{
		if (var && var->integer)
		{
			result = qtrue;
		}
		else if (!var)
		{
			result = qtrue;
		}
	}

	if (required && !result)
	{
		Ren_Fatal(MSG_ERR_OLD_VIDEO_DRIVER "\nYour GL driver is missing support for: %s\n", ext);
	}

	if (result)
	{
		Com_Printf("...found OpenGL extension - %s\n", ext);
	}
	else
	{
		if (var)
		{
			Com_Printf("...ignoring %s\n", ext);
		}
		else
		{
			Com_Printf("...%s not found\n", ext);
		}
	}

	return result;
}
Beispiel #11
0
int MemStreamRead(memStream_t *s, void *buffer, int len)
{
	int ret = 1;

	if (s == NULL || buffer == NULL)
	{
		return 0;
	}

	if (s->curPos + len > s->buffer + s->bufSize)
	{
		s->flags |= MEMSTREAM_FLAGS_EOF;
		len       = s->buffer + s->bufSize - s->curPos;
		ret       = 0;

		Ren_Fatal("MemStreamRead: EOF reached");
	}

	Com_Memcpy(buffer, s->curPos, len);
	s->curPos += len;

	return ret;
}
Beispiel #12
0
static void GLimp_DetectAvailableModes(void)
{
	int             i, j;
	char            buf[MAX_STRING_CHARS] = { 0 };
	SDL_Rect        modes[128];
	int             numModes = 0;
	int             display  = 0;
	SDL_DisplayMode windowMode;

	if (!main_window)
	{
		if (!SDL_GetNumVideoDisplays())
		{
			Ren_Fatal("There is no available display to open a game screen - %s", SDL_GetError());
			return;
		}

		// Use the zero display index
		display = 0;
	}
	else
	{
		// Detect the used display
		display = SDL_GetWindowDisplayIndex(main_window);
	}

	// was SDL_GetWindowDisplayMode
	if (SDL_GetDesktopDisplayMode(display, &windowMode) < 0)
	{
		Ren_Warning("Couldn't get desktop display mode, no resolutions detected - %s\n", SDL_GetError());
		return;
	}

	for (i = 0; i < SDL_GetNumDisplayModes(display); i++)
	{
		SDL_DisplayMode mode;

		if (SDL_GetDisplayMode(display, i, &mode) < 0)
		{
			continue;
		}

		if (!mode.w || !mode.h)
		{
			Ren_Print("Display supports any resolution\n");
			return;
		}

		if (windowMode.format != mode.format)
		{
			continue;
		}

		// SDL can give the same resolution with different refresh rates.
		// Only list resolution once.
		for (j = 0; j < numModes; j++)
		{
			if (mode.w == modes[j].w && mode.h == modes[j].h)
			{
				break;
			}
		}

		if (j != numModes)
		{
			continue;
		}

		modes[numModes].w = mode.w;
		modes[numModes].h = mode.h;
		numModes++;
	}

	if (numModes > 1)
	{
		qsort(modes, numModes, sizeof(SDL_Rect), GLimp_CompareModes);
	}

	for (i = 0; i < numModes; i++)
	{
		const char *newModeString = va("%ux%u ", modes[i].w, modes[i].h);

		if (strlen(newModeString) < (int)sizeof(buf) - strlen(buf))
		{
			Q_strcat(buf, sizeof(buf), newModeString);
		}
		else
		{
			Ren_Warning("Skipping mode %ux%u, buffer too small\n", modes[i].w, modes[i].h);
		}
	}

	if (*buf)
	{
		buf[strlen(buf) - 1] = 0;
		Ren_Print("Available modes [%i]: '%s'\n", numModes, buf);
		ri.Cvar_Set("r_availableModes", buf);
	}
}
Beispiel #13
0
static void R_BuildGammaProgram(void)
{
	GLint compiled;

	gammaProgram.vertexShader   = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
	gammaProgram.fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);

	glShaderSourceARB(gammaProgram.vertexShader, 1, (const GLcharARB **)&simpleGammaVert, NULL);
	glShaderSourceARB(gammaProgram.fragmentShader, 1, (const GLcharARB **)&simpleGammaFrag, NULL);

	glCompileShaderARB(gammaProgram.vertexShader);
	glCompileShaderARB(gammaProgram.fragmentShader);

	glGetObjectParameterivARB(gammaProgram.vertexShader, GL_COMPILE_STATUS, &compiled);
	if (!compiled)
	{
		GLint   blen = 0;
		GLsizei slen = 0;

		glGetShaderiv(gammaProgram.vertexShader, GL_INFO_LOG_LENGTH, &blen);
		if (blen > 1)
		{
			GLchar *compiler_log;

			compiler_log = (GLchar *) malloc(blen);

			glGetInfoLogARB(gammaProgram.vertexShader, blen, &slen, compiler_log);
			Ren_Fatal("Failed to compile the gamma vertex shader reason: %s\n", compiler_log);
		}
		else
		{
			Ren_Fatal("Failed to compile the gamma vertex shader\n");
		}
	}

	glGetObjectParameterivARB(gammaProgram.fragmentShader, GL_COMPILE_STATUS, &compiled);
	if (!compiled)
	{
		Ren_Fatal("Failed to compile the gamma fragment shader\n");
	}

	gammaProgram.program = glCreateProgramObjectARB();
	if (!gammaProgram.program)
	{
		Ren_Fatal("Failed to create program\n");
	}

	glAttachObjectARB(gammaProgram.program, gammaProgram.vertexShader);
	glAttachObjectARB(gammaProgram.program, gammaProgram.fragmentShader);

	glLinkProgramARB(gammaProgram.program);

	glGetProgramivARB(gammaProgram.program, GL_LINK_STATUS, &compiled); // this throws glGetError() = 0x500
	if (!compiled)
	{
		Ren_Fatal("Failed to link gamma shaders\n");
	}

	glUseProgramObjectARB(gammaProgram.program);

	gammaProgram.currentMapUniform = glGetUniformLocation(gammaProgram.program, "u_CurrentMap");
	gammaProgram.gammaUniform      = glGetUniformLocation(gammaProgram.program, "u_gamma");

	glUseProgramObjectARB(0);
}
Beispiel #14
0
/*
============
R_CreateIBO2
============
*/
IBO_t *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t *triangles, vboUsage_t usage)
{
	IBO_t         *ibo;
	int           i, j;
	byte          *indexes;
	int           indexesSize;
	int           indexesOfs;
	srfTriangle_t *tri;
	glIndex_t     index;
	int           glUsage;

	switch (usage)
	{
	case VBO_USAGE_STATIC:
		glUsage = GL_STATIC_DRAW;
		break;
	case VBO_USAGE_DYNAMIC:
		glUsage = GL_DYNAMIC_DRAW;
		break;
	default:
		glUsage = 0;
		Ren_Fatal("bad vboUsage_t given: %i", usage);
		break;
	}

	if (!numTriangles)
	{
		return NULL;
	}

	if (strlen(name) >= MAX_QPATH)
	{
		Ren_Drop("R_CreateIBO2: \"%s\" is too long\n", name);
	}

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

	ibo = (IBO_t *)ri.Hunk_Alloc(sizeof(*ibo), h_low);
	Com_AddToGrowList(&tr.ibos, ibo);

	Q_strncpyz(ibo->name, name, sizeof(ibo->name));

	indexesSize = numTriangles * 3 * sizeof(glIndex_t);
	indexes     = (byte *)ri.Hunk_AllocateTempMemory(indexesSize);
	indexesOfs  = 0;

	//Ren_Print("sizeof(glIndex_t) = %i\n", sizeof(glIndex_t));

	for (i = 0, tri = triangles; i < numTriangles; i++, tri++)
	{
		for (j = 0; j < 3; j++)
		{
			index = tri->indexes[j];
			memcpy(indexes + indexesOfs, &index, sizeof(glIndex_t));
			indexesOfs += sizeof(glIndex_t);
		}
	}

	ibo->indexesSize = indexesSize;
	ibo->indexesNum  = numTriangles * 3;

	glGenBuffers(1, &ibo->indexesVBO);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->indexesVBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexesSize, indexes, glUsage);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	GL_CheckErrors();

	ri.Hunk_FreeTempMemory(indexes);

	return ibo;
}
Beispiel #15
0
/*
============
R_CreateVBO
============
*/
VBO_t *R_CreateVBO(const char *name, byte *vertexes, int vertexesSize, vboUsage_t usage)
{
	VBO_t *vbo;
	int   glUsage;

	switch (usage)
	{
	case VBO_USAGE_STATIC:
		glUsage = GL_STATIC_DRAW;
		break;
	case VBO_USAGE_DYNAMIC:
		glUsage = GL_DYNAMIC_DRAW;
		break;
	default:
		glUsage = 0; //Prevents warning
		Ren_Fatal("bad vboUsage_t given: %i", usage);
		break;
	}

	if (strlen(name) >= MAX_QPATH)
	{
		Ren_Drop("R_CreateVBO: \"%s\" is too long\n", name);
	}

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

	vbo = (VBO_t *)ri.Hunk_Alloc(sizeof(*vbo), h_low);
	Com_AddToGrowList(&tr.vbos, vbo);

	Q_strncpyz(vbo->name, name, sizeof(vbo->name));

	vbo->ofsXYZ             = 0;
	vbo->ofsTexCoords       = 0;
	vbo->ofsLightCoords     = 0;
	vbo->ofsBinormals       = 0;
	vbo->ofsTangents        = 0;
	vbo->ofsNormals         = 0;
	vbo->ofsColors          = 0;
	vbo->ofsPaintColors     = 0;
	vbo->ofsLightDirections = 0;
	vbo->ofsBoneIndexes     = 0;
	vbo->ofsBoneWeights     = 0;

	vbo->sizeXYZ       = 0;
	vbo->sizeTangents  = 0;
	vbo->sizeBinormals = 0;
	vbo->sizeNormals   = 0;

	vbo->vertexesSize = vertexesSize;

	glGenBuffers(1, &vbo->vertexesVBO);

	glBindBuffer(GL_ARRAY_BUFFER, vbo->vertexesVBO);
	glBufferData(GL_ARRAY_BUFFER, vertexesSize, vertexes, glUsage);

	glBindBuffer(GL_ARRAY_BUFFER, 0);

	GL_CheckErrors();

	return vbo;
}
Beispiel #16
0
static void GLimp_InitExtensionsR2(void)
{
	Ren_Print("Initializing OpenGL extensions\n");

	// GL_ARB_multitexture
	if (glConfig.driverType != GLDRV_OPENGL3)
	{
		if (GLEW_ARB_multitexture)
		{
			glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &glConfig.maxActiveTextures);

			if (glConfig.maxActiveTextures > 1)
			{
				Ren_Print("...found OpenGL extension - GL_ARB_multitexture\n");
			}
			else
			{
				Ren_Fatal(MSG_ERR_OLD_VIDEO_DRIVER "\nYour GL driver is missing support for: GL_ARB_multitexture, < 2 texture units");
			}
		}
		else
		{
			Ren_Fatal(MSG_ERR_OLD_VIDEO_DRIVER "\nYour GL driver is missing support for: GL_ARB_multitexture");
		}
	}

	// GL_ARB_depth_texture
	GLimp_CheckForVersionExtension("GL_ARB_depth_texture", 130, qtrue, NULL);

	if (GLimp_CheckForVersionExtension("GL_ARB_texture_cube_map", 130, qtrue, NULL))
	{
		glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig2.maxCubeMapTextureSize);
	}
	GL_CheckErrors();

	GLimp_CheckForVersionExtension("GL_ARB_vertex_program", 210, qtrue, NULL);
	GLimp_CheckForVersionExtension("GL_ARB_vertex_buffer_object", 300, qtrue, NULL);

	// GL_ARB_occlusion_query
	glConfig2.occlusionQueryAvailable = qfalse;
	glConfig2.occlusionQueryBits      = 0;
	if (GLimp_CheckForVersionExtension("GL_ARB_occlusion_query", 150, qfalse, r_ext_occlusion_query))
	{
		glConfig2.occlusionQueryAvailable = qtrue;
		glGetQueryivARB(GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &glConfig2.occlusionQueryBits);
	}
	GL_CheckErrors();

	GLimp_CheckForVersionExtension("GL_ARB_shader_objects", 210, qtrue, NULL);

	if (GLimp_CheckForVersionExtension("GL_ARB_vertex_shader", 210, qtrue, NULL))
	{
		int reservedComponents;

		GL_CheckErrors();
		glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig2.maxVertexUniforms); GL_CheckErrors();
		//glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &glConfig.maxVaryingFloats); GL_CheckErrors();
		glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig2.maxVertexAttribs); GL_CheckErrors();

		reservedComponents = 16 * 10; // approximation how many uniforms we have besides the bone matrices

		glConfig2.maxVertexSkinningBones     = (int) Q_bound(0.0, (Q_max(glConfig2.maxVertexUniforms - reservedComponents, 0) / 16), MAX_BONES);
		glConfig2.vboVertexSkinningAvailable = (qboolean)(r_vboVertexSkinning->integer && ((glConfig2.maxVertexSkinningBones >= 12) ? qtrue : qfalse));
	}
	GL_CheckErrors();

	GLimp_CheckForVersionExtension("GL_ARB_fragment_shader", 210, qtrue, NULL);

	// GL_ARB_shading_language_100
	if (GLimp_CheckForVersionExtension("GL_ARB_shading_language_100", 210, qtrue, NULL))
	{
		Q_strncpyz(glConfig2.shadingLanguageVersion, (char *)glGetString(GL_SHADING_LANGUAGE_VERSION_ARB), sizeof(glConfig2.shadingLanguageVersion));
		sscanf(glConfig2.shadingLanguageVersion, "%d.%d", &glConfig2.glslMajorVersion, &glConfig2.glslMinorVersion);
	}
	GL_CheckErrors();

	glConfig2.textureNPOTAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_ARB_texture_non_power_of_two", 300, qfalse, r_ext_texture_non_power_of_two))
	{
		glConfig2.textureNPOTAvailable = qtrue;
	}

	glConfig2.drawBuffersAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_ARB_draw_buffers", /* -1 */ 300, qfalse, r_ext_draw_buffers))
	{
		glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &glConfig2.maxDrawBuffers);
		glConfig2.drawBuffersAvailable = qtrue;
	}

	glConfig2.textureHalfFloatAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_ARB_half_float_pixel", 300, qfalse, r_ext_half_float_pixel))
	{
		glConfig2.textureHalfFloatAvailable = qtrue;
	}

	glConfig2.textureFloatAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_ARB_texture_float", 300, qfalse, r_ext_texture_float))
	{
		glConfig2.textureFloatAvailable = qtrue;
	}

	glConfig2.ARBTextureCompressionAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_ARB_texture_compression", 300, qfalse, r_ext_compressed_textures))
	{
		glConfig2.ARBTextureCompressionAvailable = qtrue;
		glConfig.textureCompression              = TC_NONE;
	}

	glConfig2.vertexArrayObjectAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_ARB_vertex_array_object", 300, qfalse, r_ext_vertex_array_object))
	{
		glConfig2.vertexArrayObjectAvailable = qtrue;
	}

	// GL_EXT_texture_compression_s3tc
	if (GLimp_CheckForVersionExtension("GL_EXT_texture_compression_s3tc", -1, qfalse, r_ext_compressed_textures))
	{
		glConfig.textureCompression = TC_S3TC;
	}

	glConfig2.texture3DAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_EXT_texture3D", 170, qfalse, NULL))
	{
		glConfig2.texture3DAvailable = qtrue;
	}

	glConfig2.stencilWrapAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_EXT_stencil_wrap", 210, qfalse, r_ext_stencil_wrap))
	{
		glConfig2.stencilWrapAvailable = qtrue;
	}

	glConfig2.textureAnisotropyAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_EXT_texture_filter_anisotropic", -1, qfalse, r_ext_texture_filter_anisotropic))
	{
		glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig2.maxTextureAnisotropy);
		glConfig2.textureAnisotropyAvailable = qtrue;
	}
	GL_CheckErrors();

	GLimp_CheckForVersionExtension("GL_EXT_stencil_two_side", 210, qfalse, r_ext_stencil_two_side);
	GLimp_CheckForVersionExtension("GL_EXT_depth_bounds_test", 170, qfalse, r_ext_depth_bounds_test);

	glConfig2.framebufferObjectAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_EXT_framebuffer_object", 300, qfalse, r_ext_packed_depth_stencil))
	{
		glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &glConfig2.maxRenderbufferSize);
		glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &glConfig2.maxColorAttachments);

		glConfig2.framebufferObjectAvailable = qtrue;
	}
	GL_CheckErrors();

	glConfig2.framebufferPackedDepthStencilAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_EXT_packed_depth_stencil", 300, qfalse, r_ext_packed_depth_stencil) && glConfig.driverType != GLDRV_MESA)
	{
		glConfig2.framebufferPackedDepthStencilAvailable = qtrue;
	}

	glConfig2.framebufferBlitAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_EXT_framebuffer_blit", 300, qfalse, r_ext_framebuffer_blit))
	{
		glConfig2.framebufferBlitAvailable = qtrue;
	}

	// GL_EXTX_framebuffer_mixed_formats not used

	glConfig2.generateMipmapAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_SGIS_generate_mipmap", 140, qfalse, r_ext_generate_mipmap))
	{
		glConfig2.generateMipmapAvailable = qtrue;
	}

	glConfig2.getProgramBinaryAvailable = qfalse;
	if (GLimp_CheckForVersionExtension("GL_ARB_get_program_binary", 410, qfalse, NULL))
	{
		int formats = 0;

		glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &formats);

		if (formats)
		{
			glConfig2.getProgramBinaryAvailable = qtrue;
		}
	}

	// If we are in developer mode, then we will print out messages from the gfx driver
	if (GLimp_CheckForVersionExtension("GL_ARB_debug_output", 410, qfalse, NULL) && ri.Cvar_VariableIntegerValue("developer"))
	{
#ifdef GL_DEBUG_OUTPUT
		glEnable(GL_DEBUG_OUTPUT);

		if (410 <= glConfig2.contextCombined)
		{
			glDebugMessageCallback(Glimp_DebugCallback, NULL);
			glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
		}
		else
		{
			glDebugMessageCallbackARB(Glimp_DebugCallback, NULL);
			glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
		}
#endif
	}
}
Beispiel #17
0
/*
============
R_CreateVBO2
============
*/
VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t *verts, unsigned int stateBits, vboUsage_t usage)
{
	VBO_t        *vbo;
	int          i, j;
	byte         *data;
	int          dataSize;
	int          dataOfs;
	int          glUsage;
	unsigned int bits;

	switch (usage)
	{
	case VBO_USAGE_STATIC:
		glUsage = GL_STATIC_DRAW;
		break;
	case VBO_USAGE_DYNAMIC:
		glUsage = GL_DYNAMIC_DRAW;
		break;
	default:
		glUsage = 0;
		Ren_Fatal("bad vboUsage_t given: %i", usage);
		break;
	}

	if (!numVertexes)
	{
		return NULL;
	}

	if (strlen(name) >= MAX_QPATH)
	{
		Ren_Drop("R_CreateVBO2: \"%s\" is too long\n", name);
	}

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

	vbo = (VBO_t *)ri.Hunk_Alloc(sizeof(*vbo), h_low);
	Com_AddToGrowList(&tr.vbos, vbo);

	Q_strncpyz(vbo->name, name, sizeof(vbo->name));

	vbo->ofsXYZ             = 0;
	vbo->ofsTexCoords       = 0;
	vbo->ofsLightCoords     = 0;
	vbo->ofsBinormals       = 0;
	vbo->ofsTangents        = 0;
	vbo->ofsNormals         = 0;
	vbo->ofsColors          = 0;
	vbo->ofsPaintColors     = 0;
	vbo->ofsLightDirections = 0;
	vbo->ofsBoneIndexes     = 0;
	vbo->ofsBoneWeights     = 0;

	vbo->sizeXYZ       = 0;
	vbo->sizeTangents  = 0;
	vbo->sizeBinormals = 0;
	vbo->sizeNormals   = 0;

	// size VBO
	dataSize = 0;
	bits     = stateBits;
	while (bits)
	{
		if (bits & 1)
		{
			dataSize += sizeof(vec4_t);
		}
		bits >>= 1;
	}
	dataSize *= numVertexes;
	data      = (byte *)ri.Hunk_AllocateTempMemory(dataSize);
	dataOfs   = 0;

	// since this is all float, point tmp directly into data
	// 2-entry -> { memb[0], memb[1], 0, 1 }
	// 3-entry -> { memb[0], memb[1], memb[2], 1 }
#define VERTEXSIZE(memb) (sizeof(verts->memb) / sizeof(verts->memb[0]))
#define VERTEXCOPY(memb) \
	do { \
		vec_t *tmp = (vec_t *) (data + dataOfs); \
		for (i = 0; i < numVertexes; i++) \
		{ \
			for (j = 0; j < VERTEXSIZE(memb); j++) { *tmp++ = verts[i].memb[j]; } \
			if (VERTEXSIZE(memb) < 3) { *tmp++ = 0; } \
			if (VERTEXSIZE(memb) < 4) { *tmp++ = 1; } \
		} \
		dataOfs += i * sizeof(vec4_t); \
	} while (0)

	if (stateBits & ATTR_POSITION)
	{
		vbo->ofsXYZ = dataOfs;
		VERTEXCOPY(xyz);
	}

	// feed vertex texcoords
	if (stateBits & ATTR_TEXCOORD)
	{
		vbo->ofsTexCoords = dataOfs;
		VERTEXCOPY(st);
	}

	// feed vertex lightmap texcoords
	if (stateBits & ATTR_LIGHTCOORD)
	{
		vbo->ofsLightCoords = dataOfs;
		VERTEXCOPY(lightmap);
	}

	// feed vertex tangents
	if (stateBits & ATTR_TANGENT)
	{
		vbo->ofsTangents = dataOfs;
		VERTEXCOPY(tangent);
	}

	// feed vertex binormals
	if (stateBits & ATTR_BINORMAL)
	{
		vbo->ofsBinormals = dataOfs;
		VERTEXCOPY(binormal);
	}

	// feed vertex normals
	if (stateBits & ATTR_NORMAL)
	{
		vbo->ofsNormals = dataOfs;
		VERTEXCOPY(normal);
	}

	// feed vertex colors
	if (stateBits & ATTR_COLOR)
	{
		vbo->ofsColors = dataOfs;
		VERTEXCOPY(lightColor);
	}

	vbo->vertexesSize = dataSize;
	vbo->vertexesNum  = numVertexes;

	glGenBuffers(1, &vbo->vertexesVBO);

	glBindBuffer(GL_ARRAY_BUFFER, vbo->vertexesVBO);
	glBufferData(GL_ARRAY_BUFFER, dataSize, data, glUsage);

	glBindBuffer(GL_ARRAY_BUFFER, 0);

	GL_CheckErrors();

	ri.Hunk_FreeTempMemory(data);

	return vbo;
}
Beispiel #18
0
/**
 * @brief This routine is responsible for initializing the OS specific portions of OpenGL
 */
void GLimp_Init(void)
{
	r_allowSoftwareGL = ri.Cvar_Get("r_allowSoftwareGL", "0", CVAR_LATCH);
	r_allowResize     = ri.Cvar_Get("r_allowResize", "0", CVAR_ARCHIVE);
	r_centerWindow    = ri.Cvar_Get("r_centerWindow", "0", CVAR_ARCHIVE);

	if (ri.Cvar_VariableIntegerValue("com_abnormalExit"))
	{
		ri.Cvar_Set("r_mode", va("%d", R_MODE_FALLBACK));
		ri.Cvar_Set("r_fullscreen", "0");
		ri.Cvar_Set("r_centerWindow", "0");
		ri.Cvar_Set("com_abnormalExit", "0");
	}

	ri.Sys_GLimpInit();

	// Create the window and set up the context
	if (GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, r_noborder->integer))
	{
		goto success;
	}

	// Try again, this time in a platform specific "safe mode"
	ri.Sys_GLimpSafeInit();

	if (GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, qfalse))
	{
		goto success;
	}

	// Finally, try the default screen resolution
	if (r_mode->integer != R_MODE_FALLBACK)
	{
		Ren_Print("Setting r_mode %d failed, falling back on r_mode %d\n",
		          r_mode->integer, R_MODE_FALLBACK);

		if (GLimp_StartDriverAndSetMode(R_MODE_FALLBACK, qfalse, qfalse))
		{
			goto success;
		}
	}

	// Nothing worked, give up
	Ren_Fatal("GLimp_Init() - could not load OpenGL subsystem\n");

success:

	//Clear the screen with a black color thanks
	Glimp_ClearScreen();

#ifdef FEATURE_RENDERER2
	if (glConfig.driverType != GLDRV_OPENGL3)
	{
		glConfig.driverType = GLDRV_ICD;
	}
#else
	// This values force the UI to disable driver selection
	glConfig.driverType = GLDRV_ICD;
#endif
	glConfig.hardwareType = GLHW_GENERIC;

	// Only using SDL_SetWindowBrightness to determine if hardware gamma is supported
	glConfig.deviceSupportsGamma = !r_ignorehwgamma->integer &&
	                               SDL_SetWindowBrightness(main_window, 1.0f) >= 0;

	// Get extension strings
	if (glConfig.driverType != GLDRV_OPENGL3)
	{
		Q_strncpyz(glConfig.extensions_string, ( char * ) glGetString(GL_EXTENSIONS), sizeof(glConfig.extensions_string));
	}

#ifndef FEATURE_RENDERER_GLES
	else
	{
		int i = 0, exts = 0;
		glGetIntegerv(GL_NUM_EXTENSIONS, &exts);
		glConfig.extensions_string[0] = 0;
		for (i = 0; i < exts; i++)
		{
			if (strlen(glConfig.extensions_string) + 100 >= sizeof(glConfig.extensions_string))
			{
				//Just so we wont error out when there are really a lot of extensions
				break;
			}

			Q_strcat(glConfig.extensions_string, sizeof(glConfig.extensions_string), va("%s ", glGetStringi(GL_EXTENSIONS, i)));
		}
	}
#endif // FEATURE_RENDERER_GLES

	// initialize extensions
	GLimp_SetHardware();
#ifdef FEATURE_RENDERER2
	GLimp_InitExtensionsR2(); // renderer2
#else
	GLimp_InitExtensions(); // vanilla renderer
#endif

	ri.Cvar_Get("r_availableModes", "", CVAR_ROM);

	// This depends on SDL_INIT_VIDEO, hence having it here
	ri.IN_Init();
}
Beispiel #19
0
/**
 * @brief Will be called once for each RE_EndFrame
 */
void RE_BeginFrame()
{
	drawBufferCommand_t *cmd;

	if (!tr.registered)
	{
		return;
	}

	Ren_LogComment("--- RE_BeginFrame ---\n");

	glState.finishCalled = qfalse;

	tr.frameCount++;
	tr.frameSceneNum = 0;
	tr.viewCount     = 0;

	// do overdraw measurement
	if (r_measureOverdraw->integer)
	{
		if (glConfig.stencilBits < 4)
		{
			Ren_Print("Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits);
			ri.Cvar_Set("r_measureOverdraw", "0");
		}
		else if (r_shadows->integer == 2)
		{
			Ren_Print("Warning: stencil shadows and overdraw measurement are mutually exclusive\n");
			ri.Cvar_Set("r_measureOverdraw", "0");
		}
		else
		{
			R_IssuePendingRenderCommands();
			glEnable(GL_STENCIL_TEST);
			glStencilMask(~0U);
			GL_ClearStencil(0U);
			glStencilFunc(GL_ALWAYS, 0U, ~0U);
			glStencilOp(GL_KEEP, GL_INCR, GL_INCR);
		}
		r_measureOverdraw->modified = qfalse;
	}
	else
	{
		// this is only reached if it was on and is now off
		if (r_measureOverdraw->modified)
		{
			R_IssuePendingRenderCommands();
			glDisable(GL_STENCIL_TEST);
		}
		r_measureOverdraw->modified = qfalse;
	}

	// texturemode stuff
	if (r_textureMode->modified)
	{
		R_IssuePendingRenderCommands();
		GL_TextureMode(r_textureMode->string);
		r_textureMode->modified = qfalse;
	}

	// gamma stuff
	if (r_gamma->modified)
	{
		r_gamma->modified = qfalse;
		R_IssuePendingRenderCommands();
		R_SetColorMappings();
	}

	// check for errors
	if (!r_ignoreGLErrors->integer)
	{
		int  err;
		char s[128];

		R_IssuePendingRenderCommands();

		if ((err = glGetError()) != GL_NO_ERROR)
		{
			switch (err)
			{
			case GL_INVALID_ENUM:
				Q_strcpy(s, "GL_INVALID_ENUM");
				break;
			case GL_INVALID_VALUE:
				Q_strcpy(s, "GL_INVALID_VALUE");
				break;
			case GL_INVALID_OPERATION:
				Q_strcpy(s, "GL_INVALID_OPERATION");
				break;
			case GL_STACK_OVERFLOW:
				Q_strcpy(s, "GL_STACK_OVERFLOW");
				break;
			case GL_STACK_UNDERFLOW:
				Q_strcpy(s, "GL_STACK_UNDERFLOW");
				break;
			case GL_OUT_OF_MEMORY:
				Q_strcpy(s, "GL_OUT_OF_MEMORY");
				break;
			case GL_TABLE_TOO_LARGE:
				Q_strcpy(s, "GL_TABLE_TOO_LARGE");
				break;
			case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
				Q_strcpy(s, "GL_INVALID_FRAMEBUFFER_OPERATION_EXT");
				break;
			default:
				Com_sprintf(s, sizeof(s), "0x%X", err);
				break;
			}

			//Ren_Fatal( "caught OpenGL error: %s in file %s line %i", s, filename, line);
			Ren_Fatal("RE_BeginFrame() - glGetError() failed (%s)!\n", s);
		}
	}

	// draw buffer stuff
	cmd = (drawBufferCommand_t *)R_GetCommandBuffer(sizeof(*cmd));
	if (!cmd)
	{
		return;
	}

	cmd->commandId = RC_DRAW_BUFFER;

	if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
	{
		cmd->buffer = (int)GL_FRONT;
	}
	else
	{
		cmd->buffer = (int)GL_BACK;
	}
}
Beispiel #20
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;
}