int FLightBuffer::UploadLights(FDynLightData &data)
{
	int size0 = data.arrays[0].Size()/4;
	int size1 = data.arrays[1].Size()/4;
	int size2 = data.arrays[2].Size()/4;
	int totalsize = size0 + size1 + size2 + 1;

	// pointless type casting because some compilers can't print enough warnings.
	if (mBlockAlign > 0 && (unsigned int)totalsize + (mIndex % mBlockAlign) > mBlockSize)
	{
		mIndex = ((mIndex + mBlockAlign) / mBlockAlign) * mBlockAlign;

		// can't be rendered all at once.
		if ((unsigned int)totalsize > mBlockSize)
		{
			int diff = totalsize - (int)mBlockSize;

			size2 -= diff;
			if (size2 < 0)
			{
				size1 += size2;
				size2 = 0;
			}
			if (size1 < 0)
			{
				size0 += size1;
				size1 = 0;
			}
			totalsize = size0 + size1 + size2 + 1;
		}
	}

	if (totalsize <= 1) return -1;

	if (mIndex + totalsize > mBufferSize/4)
	{
		// reallocate the buffer with twice the size
		unsigned int newbuffer;

		// first unmap the old buffer
		glBindBuffer(mBufferType, mBufferId);
		glUnmapBuffer(mBufferType);

		// create and bind the new buffer, bind the old one to a copy target (too bad that DSA is not yet supported well enough to omit this crap.)
		glGenBuffers(1, &newbuffer);
		glBindBufferBase(mBufferType, LIGHTBUF_BINDINGPOINT, newbuffer);
		glBindBuffer(mBufferType, newbuffer);	// Note: Some older AMD drivers don't do that in glBindBufferBase, as they should.
		glBindBuffer(GL_COPY_READ_BUFFER, mBufferId);

		// create the new buffer's storage (twice as large as the old one)
		mBufferSize *= 2;
		mByteSize *= 2;
		if (gl.lightmethod == LM_DIRECT)
		{
			glBufferStorage(mBufferType, mByteSize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
			mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
		}
		else
		{
			glBufferData(mBufferType, mByteSize, NULL, GL_DYNAMIC_DRAW);
			mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_BUFFER_BIT);
		}

		// copy contents and delete the old buffer.
		glCopyBufferSubData(GL_COPY_READ_BUFFER, mBufferType, 0, 0, mByteSize/2);
		glBindBuffer(GL_COPY_READ_BUFFER, 0);
		glDeleteBuffers(1, &mBufferId);
		mBufferId = newbuffer;
	}

	float *copyptr;
	
	assert(mBufferPointer != NULL);
	if (mBufferPointer == NULL) return -1;
	copyptr = mBufferPointer + mIndex * 4;

	float parmcnt[] = { 0, float(size0), float(size0 + size1), float(size0 + size1 + size2) };

	memcpy(&copyptr[0], parmcnt, 4 * sizeof(float));
	memcpy(&copyptr[4], &data.arrays[0][0], 4 * size0*sizeof(float));
	memcpy(&copyptr[4 + 4*size0], &data.arrays[1][0], 4 * size1*sizeof(float));
	memcpy(&copyptr[4 + 4*(size0 + size1)], &data.arrays[2][0], 4 * size2*sizeof(float));

	unsigned int bufferindex = mIndex;
	mIndex += totalsize;
	draw_dlight += (totalsize-1) / 2;
	return bufferindex;
}
Exemplo n.º 2
0
Arquivo: font.c Projeto: needs/anko
void render_text(wchar_t * str, float x, float y, float size)
{
	float scale = size / GLYPH_DIM;
	int len = wcslen(str);
	int i;
	int buf_index = 0;
	float cur_x = 0;
	float cur_y = 0;
	float *buf;

	if(vbo_index + len > VBO_MAX_SIZE)
		return;
	
	glBindBuffer(GL_ARRAY_BUFFER, font_vbo);
	
	buf = glMapBufferRange(GL_ARRAY_BUFFER, vbo_index*glyph_data_size, (vbo_index+len)*glyph_data_size, GL_MAP_WRITE_BIT);
	for(i = 0; i < len; i++)
	{
		float *vertices = buf + buf_index * VERTEX_DATA_SIZE;
		int cc = str[i];
		if(cc > 256 || cc < 0) continue; // well we don't know this char
		int cc_w = droid.width[cc]; // current char width

		if(cc == '\n')
		{
			cur_x = 0;
			cur_y += GLYPH_DIM*scale;
			continue;
		}

		/* pos */
		vertices[0] = x+cur_x;
		vertices[1] = y+cur_y;
		/* uv */
		vertices[2] = glyph_data[cc][2];
		vertices[3] = glyph_data[cc][3];
		/* color */
		memcpy(&vertices[4], color, 4*sizeof(float));

		/* pos */
		vertices[8] = x+cur_x;
		vertices[9] = y+cur_y + GLYPH_DIM*scale;
		/* uv */
		vertices[10] = glyph_data[cc][6];
		vertices[11] = glyph_data[cc][7];
		/* color */
		memcpy(&vertices[12], color, 4*sizeof(float));

		/* pos */
		vertices[16] = x+cur_x + cc_w*scale;
		vertices[17] = y+cur_y + GLYPH_DIM*scale;
		/* uv */
		vertices[18] = glyph_data[cc][10];
		vertices[19] = glyph_data[cc][11];
		/* color */
		memcpy(&vertices[20], color, 4*sizeof(float));
		
		vertices[24] = x+cur_x + cc_w*scale;
		vertices[25] = y+cur_y;
		vertices[26] = glyph_data[cc][14];
		vertices[27] = glyph_data[cc][15];
		memcpy(&vertices[28], color, 4*sizeof(float));
		
		cur_x += cc_w*scale;
		buf_index++; // how many data wrote
	}
	glUnmapBuffer(GL_ARRAY_BUFFER);
	vbo_index+=buf_index;
}
	bool render()
	{
		glm::vec2 WindowSize(this->getWindowSize());

		{
			glBindBuffer(GL_UNIFORM_BUFFER, BufferName[buffer::TRANSFORM]);
			glm::mat4* Pointer = (glm::mat4*)glMapBufferRange(
				GL_UNIFORM_BUFFER, 0,	sizeof(glm::mat4),
				GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

			glm::mat4 Projection = glm::perspectiveFov(glm::pi<float>() * 0.25f, WindowSize.x, WindowSize.y, 0.1f, 100.0f);
			glm::mat4 Model = glm::mat4(1.0f);
			*Pointer = Projection * this->view() * Model;

			// Make sure the uniform buffer is uploaded
			glUnmapBuffer(GL_UNIFORM_BUFFER);
		}

		glViewportIndexedf(0, 0, 0, WindowSize.x, WindowSize.y);
		glClearBufferfv(GL_COLOR, 0, &glm::vec4(1.0f)[0]);

		glBindProgramPipeline(PipelineName);
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D_ARRAY, TextureName);
		glBindVertexArray(VertexArrayName);
		glBindBufferBase(GL_UNIFORM_BUFFER, semantic::uniform::TRANSFORM0, BufferName[buffer::TRANSFORM]);

		glBeginQuery(GL_VERTICES_SUBMITTED_ARB, this->QueryName[statistics::VERTICES_SUBMITTED]);
		glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB, this->QueryName[statistics::PRIMITIVES_SUBMITTED]);
		glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, this->QueryName[statistics::VERTEX_SHADER_INVOCATIONS]);
		glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB, this->QueryName[statistics::TESS_CONTROL_SHADER_PATCHES]);
		glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB, this->QueryName[statistics::TESS_EVALUATION_SHADER_INVOCATIONS]);
		glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS, this->QueryName[statistics::GEOMETRY_SHADER_INVOCATIONS]);
		glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB, this->QueryName[statistics::GEOMETRY_SHADER_PRIMITIVES_EMITTED]);
		glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, this->QueryName[statistics::FRAGMENT_SHADER_INVOCATIONS]);
		glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB, this->QueryName[statistics::COMPUTE_SHADER_INVOCATIONS]);
		glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB, this->QueryName[statistics::CLIPPING_INPUT_PRIMITIVES]);
		glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB, this->QueryName[statistics::CLIPPING_OUTPUT_PRIMITIVES]);
			glDrawElementsInstancedBaseVertexBaseInstance(GL_TRIANGLES, ElementCount, GL_UNSIGNED_SHORT, 0, 1, 0, 0);
		glEndQuery(GL_VERTICES_SUBMITTED_ARB);
		glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB);
		glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB);
		glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB);
		glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB);
		glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS);
		glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB);
		glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB);
		glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB);
		glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB);
		glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB);

		std::array<GLuint, statistics::MAX> QueryResult;
		for(std::size_t i = 0; i < QueryResult.size(); ++i)
			glGetQueryObjectuiv(this->QueryName[i], GL_QUERY_RESULT, &QueryResult[i]);

		fprintf(stdout, "Verts: %d; Prims: (%d, %d); Shaders(%d, %d, %d, %d, %d, %d); Clip(%d, %d)\r",
			QueryResult[statistics::VERTICES_SUBMITTED],
			QueryResult[statistics::PRIMITIVES_SUBMITTED],
			QueryResult[statistics::GEOMETRY_SHADER_PRIMITIVES_EMITTED],
			QueryResult[statistics::VERTEX_SHADER_INVOCATIONS],
			QueryResult[statistics::TESS_CONTROL_SHADER_PATCHES],
			QueryResult[statistics::TESS_EVALUATION_SHADER_INVOCATIONS],
			QueryResult[statistics::GEOMETRY_SHADER_INVOCATIONS],
			QueryResult[statistics::FRAGMENT_SHADER_INVOCATIONS],
			QueryResult[statistics::COMPUTE_SHADER_INVOCATIONS],
			QueryResult[statistics::CLIPPING_INPUT_PRIMITIVES],
			QueryResult[statistics::CLIPPING_OUTPUT_PRIMITIVES]);

		return true;
	}
Exemplo n.º 4
0
void *GPUBuffer::map(unsigned byte_size, unsigned access /*= GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT*/)
{
	KS_ASSERT(byte_size <= m_size);
    bind();
	return glMapBufferRange(m_target, 0, byte_size, access);
}
Exemplo n.º 5
0
void RefreshScreen(const void *data, unsigned width, unsigned height, size_t pitch)
{
    //Draw a textured quad with graphics
	gTexture.width = width;
	gTexture.height = height;
	const uint32_t dataSize = width*height * 4;
	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gPBO);
	glBufferData(GL_PIXEL_UNPACK_BUFFER, dataSize, NULL, GL_DYNAMIC_DRAW);
	GLubyte* ptr = (GLubyte*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, dataSize, GL_MAP_WRITE_BIT);

	if (ptr == NULL)
	    return;

	uint32_t* dst = (uint32_t*)ptr;

	memcpy(dst, data, dataSize);

	glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); // release the mapped buffer
	glBindTexture(GL_TEXTURE_2D, gTexture.glName);
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
	glActiveTexture(GL_TEXTURE0);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
	// Set clamping modes
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	//glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gFBO);
	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

// Render to the screen
        // Render on the whole framebuffer, complete from the lower left corner to the upper right
    //Draw on screen
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
	glViewport(0,0,640,480);

	// Clear the screen
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Use our shader
	glUseProgram(gProgramId);

	// Bind our texture in Texture Unit 0
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, gTexture.glName);
	// Set our "renderedTexture" sampler to user Texture Unit 0
	glUniform1i(gTexID, 0);

    //Draw the vertices
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, gQuad_vertexbuffer);
    glVertexAttribPointer(
			0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
			3,                  // size
			GL_FLOAT,           // type
			GL_FALSE,           // normalized?
			0,                  // stride
			(void*)0            // array buffer offset
    );

    // Draw the triangles !
    glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles

    glDisableVertexAttribArray(0);

}
Exemplo n.º 6
0
    void startup(void)
    {
        int i, j;

        load_shaders();

        vmath::vec4 * initial_positions = new vmath::vec4 [POINTS_TOTAL];
        vmath::vec3 * initial_velocities = new vmath::vec3 [POINTS_TOTAL];
        vmath::ivec4 * connection_vectors = new vmath::ivec4 [POINTS_TOTAL];

        int n = 0;

        for (j = 0; j < POINTS_Y; j++) {
            float fj = (float)j / (float)POINTS_Y;
            for (i = 0; i < POINTS_X; i++) {
                float fi = (float)i / (float)POINTS_X;

                initial_positions[n] = vmath::vec4((fi - 0.5f) * (float)POINTS_X,
                                                   (fj - 0.5f) * (float)POINTS_Y,
                                                   0.6f * sinf(fi) * cosf(fj),
                                                   1.0f);
                initial_velocities[n] = vmath::vec3(0.0f);

                connection_vectors[n] = vmath::ivec4(-1);

                if (j != (POINTS_Y - 1))
                {
                    if (i != 0)
                        connection_vectors[n][0] = n - 1;

                    if (j != 0)
                        connection_vectors[n][1] = n - POINTS_X;

                    if (i != (POINTS_X - 1))
                        connection_vectors[n][2] = n + 1;

                    if (j != (POINTS_Y - 1))
                        connection_vectors[n][3] = n + POINTS_X;
                }
                n++;
            }
        }

        glGenVertexArrays(2, m_vao);
        glGenBuffers(5, m_vbo);

        for (i = 0; i < 2; i++) {
            glBindVertexArray(m_vao[i]);

            glBindBuffer(GL_ARRAY_BUFFER, m_vbo[POSITION_A + i]);
            glBufferData(GL_ARRAY_BUFFER, POINTS_TOTAL * sizeof(vmath::vec4), initial_positions, GL_DYNAMIC_COPY);
            glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);
            glEnableVertexAttribArray(0);

            glBindBuffer(GL_ARRAY_BUFFER, m_vbo[VELOCITY_A + i]);
            glBufferData(GL_ARRAY_BUFFER, POINTS_TOTAL * sizeof(vmath::vec3), initial_velocities, GL_DYNAMIC_COPY);
            glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
            glEnableVertexAttribArray(1);

            glBindBuffer(GL_ARRAY_BUFFER, m_vbo[CONNECTION]);
            glBufferData(GL_ARRAY_BUFFER, POINTS_TOTAL * sizeof(vmath::ivec4), connection_vectors, GL_STATIC_DRAW);
            glVertexAttribIPointer(2, 4, GL_INT, 0, NULL);
            glEnableVertexAttribArray(2);
        }

        delete [] connection_vectors;
        delete [] initial_velocities;
        delete [] initial_positions;

        glGenTextures(2, m_pos_tbo);
        glBindTexture(GL_TEXTURE_BUFFER, m_pos_tbo[0]);
        glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_vbo[POSITION_A]);
        glBindTexture(GL_TEXTURE_BUFFER, m_pos_tbo[1]);
        glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_vbo[POSITION_B]);

        int lines = (POINTS_X - 1) * POINTS_Y + (POINTS_Y - 1) * POINTS_X;

        glGenBuffers(1, &m_index_buffer);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, lines * 2 * sizeof(int), NULL, GL_STATIC_DRAW);

        int * e = (int *)glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, lines * 2 * sizeof(int), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

        for (j = 0; j < POINTS_Y; j++)  
        {
            for (i = 0; i < POINTS_X - 1; i++)
            {
                *e++ = i + j * POINTS_X;
                *e++ = 1 + i + j * POINTS_X;
            }
        }

        for (i = 0; i < POINTS_X; i++)
        {
            for (j = 0; j < POINTS_Y - 1; j++)
            {
                *e++ = i + j * POINTS_X;
                *e++ = POINTS_X + i + j * POINTS_X;
            }
        }

        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
    }
void raytracer_app::render(double currentTime)
{
    static const GLfloat zeros[] = { 0.0f, 0.0f, 0.0f, 0.0f };
    static const GLfloat gray[] = { 0.1f, 0.1f, 0.1f, 0.0f };
    static const GLfloat ones[] = { 1.0f };
    static double last_time = 0.0;
    static double total_time = 0.0;

    if (!paused)
        total_time += (currentTime - last_time);
    last_time = currentTime;

    float f = (float)total_time;

    vmath::vec3 view_position = vmath::vec3(sinf(f * 0.3234f) * 28.0f, cosf(f * 0.4234f) * 28.0f, cosf(f * 0.1234f) * 28.0f); // sinf(f * 0.2341f) * 20.0f - 8.0f);
    vmath::vec3 lookat_point = vmath::vec3(sinf(f * 0.214f) * 8.0f, cosf(f * 0.153f) * 8.0f, sinf(f * 0.734f) * 8.0f);
    vmath::mat4 view_matrix = vmath::lookat(view_position,
                                            lookat_point,
                                            vmath::vec3(0.0f, 1.0f, 0.0f));

    glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniforms_buffer);
    uniforms_block * block = (uniforms_block *)glMapBufferRange(GL_UNIFORM_BUFFER,
                                                                0,
                                                                sizeof(uniforms_block),
                                                                GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

    vmath::mat4 model_matrix = vmath::scale(7.0f);

    // f = 0.0f;

    block->mv_matrix = view_matrix * model_matrix;
    block->view_matrix = view_matrix;
    block->proj_matrix = vmath::perspective(50.0f,
                                            (float)info.windowWidth / (float)info.windowHeight,
                                            0.1f,
                                            1000.0f);

    glUnmapBuffer(GL_UNIFORM_BUFFER);

    glBindBufferBase(GL_UNIFORM_BUFFER, 1, sphere_buffer);
    sphere * s = (sphere *)glMapBufferRange(GL_UNIFORM_BUFFER, 0, 128 * sizeof(sphere), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

    int i;

    for (i = 0; i < 128; i++)
    {
        // float f = 0.0f;
        float fi = (float)i / 128.0f;
        s[i].center = vmath::vec3(sinf(fi * 123.0f + f) * 15.75f, cosf(fi * 456.0f + f) * 15.75f, (sinf(fi * 300.0f + f) * cosf(fi * 200.0f + f)) * 20.0f);
        s[i].radius = fi * 2.3f + 3.5f;
        float r = fi * 61.0f;
        float g = r + 0.25f;
        float b = g + 0.25f;
        r = (r - floorf(r)) * 0.8f + 0.2f;
        g = (g - floorf(g)) * 0.8f + 0.2f;
        b = (b - floorf(b)) * 0.8f + 0.2f;
        s[i].color = vmath::vec4(r, g, b, 1.0f);
    }

    glUnmapBuffer(GL_UNIFORM_BUFFER);

    glBindBufferBase(GL_UNIFORM_BUFFER, 2, plane_buffer);
    plane * p = (plane *)glMapBufferRange(GL_UNIFORM_BUFFER, 0, 128 * sizeof(plane), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

    //for (i = 0; i < 1; i++)
    {
        p[0].normal = vmath::vec3(0.0f, 0.0f, -1.0f);
        p[0].d = 30.0f;

        p[1].normal = vmath::vec3(0.0f, 0.0f, 1.0f);
        p[1].d = 30.0f;

        p[2].normal = vmath::vec3(-1.0f, 0.0f, 0.0f);
        p[2].d = 30.0f;

        p[3].normal = vmath::vec3(1.0f, 0.0f, 0.0f);
        p[3].d = 30.0f;

        p[4].normal = vmath::vec3(0.0f, -1.0f, 0.0f);
        p[4].d = 30.0f;

        p[5].normal = vmath::vec3(0.0f, 1.0f, 0.0f);
        p[5].d = 30.0f;
    }

    glUnmapBuffer(GL_UNIFORM_BUFFER);

    glBindBufferBase(GL_UNIFORM_BUFFER, 3, light_buffer);
    light * l = (light *)glMapBufferRange(GL_UNIFORM_BUFFER, 0, 128 * sizeof(light), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

    f *= 1.0f;

    for (i = 0; i < 128; i++)
    {
        float fi = 3.33f - (float)i; //  / 35.0f;
        l[i].position = vmath::vec3(sinf(fi * 2.0f - f) * 15.75f,
                                    cosf(fi * 5.0f - f) * 5.75f,
                                    (sinf(fi * 3.0f - f) * cosf(fi * 2.5f - f)) * 19.4f);
    }

    glUnmapBuffer(GL_UNIFORM_BUFFER);

    glBindVertexArray(vao);
    glViewport(0, 0, info.windowWidth, info.windowHeight);

    glUseProgram(prepare_program);
    glUniformMatrix4fv(uniforms.ray_lookat, 1, GL_FALSE, view_matrix);
    glUniform3fv(uniforms.ray_origin, 1, view_position);
    glUniform1f(uniforms.aspect, (float)info.windowHeight / (float)info.windowWidth);
    glBindFramebuffer(GL_FRAMEBUFFER, ray_fbo[0]);
    static const GLenum draw_buffers[] =
    {
        GL_COLOR_ATTACHMENT0,
        GL_COLOR_ATTACHMENT1,
        GL_COLOR_ATTACHMENT2,
        GL_COLOR_ATTACHMENT3,
        GL_COLOR_ATTACHMENT4,
        GL_COLOR_ATTACHMENT5
    };
    glDrawBuffers(6, draw_buffers);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glUseProgram(trace_program);
    recurse(0);

    glUseProgram(blit_program);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glDrawBuffer(GL_BACK);

    glActiveTexture(GL_TEXTURE0);
    switch (debug_mode)
    {
        case DEBUG_NONE:
            glBindTexture(GL_TEXTURE_2D, tex_composite);
            break;
        case DEBUG_REFLECTED:
            glBindTexture(GL_TEXTURE_2D, tex_reflected[debug_depth]);
            break;
        case DEBUG_REFRACTED:
            glBindTexture(GL_TEXTURE_2D, tex_refracted[debug_depth]);
            break;
        case DEBUG_REFLECTED_COLOR:
            glBindTexture(GL_TEXTURE_2D, tex_reflection_intensity[debug_depth]);
            break;
        case DEBUG_REFRACTED_COLOR:
            glBindTexture(GL_TEXTURE_2D, tex_refraction_intensity[debug_depth]);
            break;
    }
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    /*
    glClearBufferfv(GL_COLOR, 0, gray);
    glClearBufferfv(GL_DEPTH, 0, ones);


    glBindVertexArray(vao);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    */
}