Esempio n. 1
0
/**
 * @brief Upload data to a sub-position in already-created buffer. You could also use this function to
 * resize an existing buffer without uploading data, although it won't make the
 * buffer smaller.
 * @param data_offset Whether the data pointer should be offset by start or not.
 */
void R_UploadToSubBuffer(r_buffer_t *buffer, const size_t start, const size_t size, const void *data,
                         const _Bool data_offset) {

	assert(buffer->bufnum != 0);

	// Check size. This is benign really, but it's usually a bug.
	if (!size) {
		Com_Warn("Attempted to upload 0 bytes to GPU\n");
		return;
	}

	// Don't allow null ptrs since bufferSubData does not allow it.
	if (!data) {
		Com_Error(ERROR_DROP, "Fatal: attempted to upload null to GPU. bufferSubData does not allow this.\n");
	}

	// offset ptr if requested
	if (start && data && data_offset) {
		data += start;
	}

	R_BindBuffer(buffer);

	// if the buffer isn't big enough to hold what we had already,
	// we have to resize the buffer
	const size_t total_size = start + size;

	if (total_size > buffer->size) {
		// if we passed a "start", the data is offset, so
		// just reset to null. This is an odd edge case and
		// it's fairly rare you'll be editing at the end first,
		// but who knows.
		if (start) {

			glBufferData(buffer->target, total_size, NULL, buffer->hint);
			R_GetError("Partial resize");
			r_view.buffer_stats[buffer->type].num_full_uploads++;
			glBufferSubData(buffer->target, start, size, data);
			R_GetError("Partial update");
			r_view.buffer_stats[buffer->type].num_partial_uploads++;
		} else {
			glBufferData(buffer->target, total_size, data, buffer->hint);
			R_GetError("Full resize");
			r_view.buffer_stats[buffer->type].num_full_uploads++;
		}

		r_state.buffers_total_bytes -= buffer->size;
		r_state.buffers_total_bytes += total_size;

		buffer->size = total_size;
	} else {
		// just update the range we specified
		glBufferSubData(buffer->target, start, size, data);
		R_GetError("Updating existing buffer");
		r_view.buffer_stats[buffer->type].num_partial_uploads++;
	}

	r_view.buffer_stats[buffer->type].size_uploaded += size;
}
Esempio n. 2
0
/*
 * @brief Uploads the specified image to the OpenGL implementation. Images that
 * do not have a GL texture reserved (which is most diffuse textures) will have
 * one generated for them. This flexibility allows for explicitly managed
 * textures (such as lightmaps) to be here as well.
 */
void R_UploadImage(r_image_t *image, GLenum format, byte *data) {

	if (!image || !data) {
		Com_Error(ERR_DROP, "NULL image or data\n");
	}

	if (!image->texnum) {
		glGenTextures(1, &(image->texnum));
	}

	R_BindTexture(image->texnum);

	if (image->type & IT_MASK_MIPMAP) {
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, r_image_state.filter_min);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, r_image_state.filter_mag);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_image_state.anisotropy);
		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
	} else {
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, r_image_state.filter_mag);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, r_image_state.filter_mag);
		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
	}

	glTexImage2D(GL_TEXTURE_2D, 0, format, image->width, image->height, 0, format,
			GL_UNSIGNED_BYTE, data);

	R_RegisterMedia((r_media_t *) image);

	R_GetError(image->media.name);
}
Esempio n. 3
0
/*
 * @brief
 */
void R_AttributePointer(const char *name, GLuint size, GLvoid *array) {
	r_attribute_t attribute;

	R_ProgramVariable(&attribute, R_ATTRIBUTE, name);

	qglVertexAttribPointer(attribute.location, size, GL_FLOAT, GL_FALSE, 0, array);

	R_GetError(name);
}
Esempio n. 4
0
/*
 * @brief
 */
static r_program_t *R_LoadProgram(const char *name, void(*Init)(void)) {
	r_program_t *prog;
	char log[MAX_STRING_CHARS];
	uint32_t e;
	int32_t i;

	for (i = 0; i < MAX_PROGRAMS; i++) {
		prog = &r_state.programs[i];

		if (!prog->id)
			break;
	}

	if (i == MAX_PROGRAMS) {
		Com_Warn("MAX_PROGRAMS reached\n");
		return NULL;
	}

	g_strlcpy(prog->name, name, sizeof(prog->name));

	prog->id = qglCreateProgram();

	prog->v = R_LoadShader(GL_VERTEX_SHADER, va("%s_vs.glsl", name));
	prog->f = R_LoadShader(GL_FRAGMENT_SHADER, va("%s_fs.glsl", name));

	if (prog->v)
		qglAttachShader(prog->id, prog->v->id);
	if (prog->f)
		qglAttachShader(prog->id, prog->f->id);

	qglLinkProgram(prog->id);

	qglGetProgramiv(prog->id, GL_LINK_STATUS, &e);
	if (!e) {
		qglGetProgramInfoLog(prog->id, sizeof(log) - 1, NULL, log);
		Com_Warn("%s: %s\n", prog->name, log);

		R_ShutdownProgram(prog);
		return NULL;
	}

	prog->Init = Init;

	if (prog->Init) { // invoke initialization function
		R_UseProgram(prog);

		prog->Init();

		R_UseProgram(NULL);
	}

	R_GetError(prog->name);

	return prog;
}
Esempio n. 5
0
/*
 * @brief
 */
static void R_ShutdownProgram(r_program_t *prog) {

	if (prog->v)
		R_ShutdownShader(prog->v);
	if (prog->f)
		R_ShutdownShader(prog->f);

	qglDeleteProgram(prog->id);

	R_GetError(prog->name);

	memset(prog, 0, sizeof(r_program_t));
}
Esempio n. 6
0
/*
 * @brief
 */
void R_DisableAttribute(r_attribute_t *attribute) {

	if (!attribute || attribute->location == -1) {
		Com_Warn("NULL or invalid attribute\n");
		return;
	}

	if (attribute->value.i != 0) {
		qglDisableVertexAttribArray(attribute->location);
		attribute->value.i = 0;
	}

	R_GetError(attribute->name);
}
Esempio n. 7
0
/*
 * R_ProgramParameter1i
 */
void R_ProgramParameter1i(r_uniform1i_t *variable, GLint value) {

	if (!variable || variable->location == -1) {
		Com_Warn("NULL or invalid variable\n");
		return;
	}

	if (variable->value.i == value)
		return;

	qglUniform1i(variable->location, value);
	variable->value.i = value;

	R_GetError(variable->name);
}
Esempio n. 8
0
/*
 * R_ProgramParameter3fv
 */
void R_ProgramParameter3fv(r_uniform3fv_t *variable, GLfloat *value) {

	if (!variable || variable->location == -1) {
		Com_Warn("NULL or invalid variable\n");
		return;
	}

	if (VectorCompare(variable->value.vec3, value))
		return;

	qglUniform3fv(variable->location, 1, value);
	VectorCopy(value, variable->value.vec3);

	R_GetError(variable->name);
}
Esempio n. 9
0
/**
 * @brief Upload data to an already-created buffer. You could also use this function to
 * resize an existing buffer without uploading data, although it won't make the
 * buffer smaller.
 */
void R_UploadToBuffer(r_buffer_t *buffer, const size_t size, const void *data) {

	assert(buffer->bufnum != 0);

	// Check size. This is benign really, but it's usually a bug.
	if (!size) {
		Com_Warn("Attempted to upload 0 bytes to GPU");
		return;
	}

	R_BindBuffer(buffer);

	// if the buffer isn't big enough to hold what we had already,
	// we have to resize the buffer

	if (size > buffer->size) {
		r_state.buffers_total_bytes -= buffer->size;
		r_state.buffers_total_bytes += size;

		glBufferData(buffer->target, size, data, buffer->hint);
		R_GetError("Full resize");
		r_view.buffer_stats[buffer->type].num_full_uploads++;

		buffer->size = size;
	} else {
		// just update the range we specified
		if (data) {
			glBufferSubData(buffer->target, 0, size, data);
			r_view.buffer_stats[buffer->type].num_partial_uploads++;

			R_GetError("Updating existing buffer");
		}
	}

	r_view.buffer_stats[buffer->type].size_uploaded += size;
}
Esempio n. 10
0
/**
 * @brief
 */
static void R_AddStains_UploadSurfaces(gpointer key, gpointer value, gpointer userdata) {

    r_bsp_surface_t *surf = (r_bsp_surface_t *) value;

    R_BindDiffuseTexture(surf->stainmap->texnum);
    glTexSubImage2D(GL_TEXTURE_2D, 0,
                    surf->lightmap_s, surf->lightmap_t,
                    surf->lightmap_size[0], surf->lightmap_size[1],
                    GL_RGB,
                    GL_UNSIGNED_BYTE, surf->stainmap_buffer);

    R_GetError(surf->texinfo->name);

    // mark the surface as having been modified, so reset knows it's resettable
    surf->stainmap_dirty = true;
}
Esempio n. 11
0
/**
 * @brief
 */
void R_UnbindBuffer(const r_buffer_type_t type) {

	if (!r_state.active_buffers[type]) {
		return;
	}

	r_state.active_buffers[type] = 0;

	glBindBuffer(R_BufferTypeToTarget(type), 0);

	r_view.num_state_changes[R_STATE_BIND_BUFFER]++;
	
	r_view.buffer_stats[type].bound++;

	R_GetError(NULL);
}
Esempio n. 12
0
/*
 * @brief
 */
void R_UseProgram(r_program_t *prog) {

	if (!qglUseProgram || r_state.active_program == prog)
		return;

	r_state.active_program = prog;

	if (prog) {
		qglUseProgram(prog->id);

		if (prog->Use) // invoke use function
			prog->Use();
	} else {
		qglUseProgram(0);
	}

	R_GetError(NULL);
}
Esempio n. 13
0
/**
 * @brief
 */
void R_BindBuffer(const r_buffer_t *buffer) {

	assert(buffer->bufnum != 0);

	if (r_state.active_buffers[buffer->type] == buffer->bufnum) {
		return;
	}

	r_state.active_buffers[buffer->type] = buffer->bufnum;

	glBindBuffer(buffer->target, buffer->bufnum);

	r_view.num_state_changes[R_STATE_BIND_BUFFER]++;

	r_view.buffer_stats[buffer->type].bound++;

	R_GetError(NULL);
}
Esempio n. 14
0
/*
 * @brief Free event listener for models.
 */
static void R_FreeModel(r_media_t *self) {
	r_model_t *mod = (r_model_t *) self;

	if (mod->vertex_buffer)
		qglDeleteBuffers(1, &mod->vertex_buffer);

	if (mod->texcoord_buffer)
		qglDeleteBuffers(1, &mod->texcoord_buffer);

	if (mod->lightmap_texcoord_buffer)
		qglDeleteBuffers(1, &mod->lightmap_texcoord_buffer);

	if (mod->normal_buffer)
		qglDeleteBuffers(1, &mod->normal_buffer);

	if (mod->tangent_buffer)
		qglDeleteBuffers(1, &mod->tangent_buffer);

	R_GetError(mod->media.name);
}
Esempio n. 15
0
/*
 * @brief Allocates and populates static VBO's for the specified r_model_t.
 */
static void R_LoadVertexBuffers(r_model_t *mod) {

	if (!qglGenBuffers)
		return;

	if (IS_MESH_MODEL(mod) && mod->mesh->num_frames > 1) // animated models don't use VBO
		return;

	const GLsizei v = mod->num_verts * 3 * sizeof(GLfloat);
	const GLsizei st = mod->num_verts * 2 * sizeof(GLfloat);
	const GLsizei t = mod->num_verts * 4 * sizeof(GLfloat);

	// load the vertex buffer objects
	qglGenBuffers(1, &mod->vertex_buffer);
	qglBindBuffer(GL_ARRAY_BUFFER, mod->vertex_buffer);
	qglBufferData(GL_ARRAY_BUFFER, v, mod->verts, GL_STATIC_DRAW);

	qglGenBuffers(1, &mod->texcoord_buffer);
	qglBindBuffer(GL_ARRAY_BUFFER, mod->texcoord_buffer);
	qglBufferData(GL_ARRAY_BUFFER, st, mod->texcoords, GL_STATIC_DRAW);

	qglGenBuffers(1, &mod->normal_buffer);
	qglBindBuffer(GL_ARRAY_BUFFER, mod->normal_buffer);
	qglBufferData(GL_ARRAY_BUFFER, v, mod->normals, GL_STATIC_DRAW);

	qglGenBuffers(1, &mod->tangent_buffer);
	qglBindBuffer(GL_ARRAY_BUFFER, mod->tangent_buffer);
	qglBufferData(GL_ARRAY_BUFFER, t, mod->tangents, GL_STATIC_DRAW);

	if (mod->lightmap_texcoords) {
		qglGenBuffers(1, &mod->lightmap_texcoord_buffer);
		qglBindBuffer(GL_ARRAY_BUFFER, mod->lightmap_texcoord_buffer);
		qglBufferData(GL_ARRAY_BUFFER, st, mod->lightmap_texcoords, GL_STATIC_DRAW);
	}

	qglBindBuffer(GL_ARRAY_BUFFER, 0);

	R_GetError(mod->media.name);
}