void onDraw(Graphics& g){
		g.pointSize(renderMode+0.5);
		g.color(RGB(1));
		mesh.colors().reset();
		switch (renderMode) {
			case 0:
				// do it on the CPU:
				for (int k=0; k<N; k++) {
				for (int j=0; j<N; j++) {
				for (int i=0; i<N; i++) {
					Color color;
					data.read_interp(color.components, i,j,k);
					mesh.color(color);
				}}}
				g.draw(mesh);
				break;
			case 1:
				// use 3D texcoords:
				tex.bind();
				g.draw(mesh);
				tex.unbind();
				break;
			case 2:
				// use shader:
				shader.begin();
				tex.bind();
				g.draw(mesh);
				tex.unbind();
				shader.end();
				break;
			default:;
		}
	}
inline void OmniStereoGraphicsRenderer::onDrawOmni(OmniStereo& omni) {
  graphics().error("start onDraw");
  mShader.begin();
  mOmni.uniforms(mShader);
  graphics().pushMatrix(graphics().MODELVIEW);
  onDraw(graphics());
  graphics().popMatrix(graphics().MODELVIEW);
  mShader.end();
}
inline bool OmniStereoGraphicsRenderer::onCreate() {
  mOmni.onCreate();

  Shader vert, frag;
  vert.source(OmniStereo::glsl() + vertexCode(), Shader::VERTEX).compile();
  vert.printLog();
  frag.source(fragmentCode(), Shader::FRAGMENT).compile();
  frag.printLog();
  mShader.attach(vert).attach(frag).link();
  mShader.printLog();
  mShader.begin();
  mShader.uniform("lighting", 0.0);
  mShader.uniform("texture", 0.0);
  mShader.end();

  return true;
}
Example #4
0
void run()
{
	if(!initialize())
		shutdown("Failed to initialize");

	if(!loadContent())
		shutdown("Failed to load resources");	

	Mesh cubeMesh = Mesh::genUnitColoredCube();
	MeshBuffer cubeBuffer(cubeMesh);
	Model cube(cubeBuffer);

	Mesh waterMesh = Mesh::genUnitColoredPlane(Color(0.57f, 0.63f, 0.98f));
	MeshBuffer waterBuffer(waterMesh);
	Model water(waterBuffer);

	BufferObject quadVbo;
	float quadVertices[] = {
		-1.0f, -1.0f, 0.0f, 0.0f,
		+1.0f, -1.0f, 1.0f, 0.0f,
		+1.0f, +1.0f, 1.0f, 1.0f,
		+1.0f, +1.0f, 1.0f, 1.0f,
		-1.0f, +1.0f, 0.0f, 1.0f,
		-1.0f, -1.0f, 0.0f, 0.0f
	};
	quadVbo.create(GL_ARRAY_BUFFER, GL_STATIC_DRAW, sizeof(quadVertices), quadVertices);

	Mesh gridMesh;
	for(int i = 0; i <= 8; ++i)
	{
		float f = (i / 8.0) * 2.0f - 1.0f;
		int j = gridMesh.getPositionCount();
		gridMesh.addPosition(f * 3.0f, 0.0f, -3.0f);
		gridMesh.addPosition(f * 3.0f, 0.0f, +3.0f);
		gridMesh.addPosition(-3.0f, 0.0f, f * 3.0f);
		gridMesh.addPosition(+3.0f, 0.0f, f * 3.0f);
		gridMesh.addColor(Colors::White);
		gridMesh.addColor(Colors::White);
		gridMesh.addColor(Colors::White);
		gridMesh.addColor(Colors::White);
		gridMesh.addIndex(j + 0); gridMesh.addIndex(j + 1);
		gridMesh.addIndex(j + 2); gridMesh.addIndex(j + 3);
	}
	MeshBuffer gridBuffer(gridMesh);
	Model grid(gridBuffer);

	VertexArray vao;
	vao.create();
	vao.bind();

	mat4 perspectiveMatrix = glm::perspective(45.0f, windowWidth / float(windowHeight), 0.05f, 50.0f);
	
	// The geometry to be refracted and reflected are stored in these
	// In addition to RGB values, the world-space height is stored in the alpha-channel
	// of the refraction texture.
	// Fresnel equations is used to blend between the two textures
	RenderTexture refractionRT(windowWidth, windowHeight);
	RenderTexture reflectionRT(windowWidth, windowHeight);

	renderer.setClearColor(0.55f, 0.45f, 0.45f, 1.0f);
	renderer.setClearDepth(1.0);

	Timer timer;
	timer.start();
	double renderTime = 0.0;

	while(context.isOpen())
	{
		timer.step();
		double time = timer.getElapsedTime();
		update(time, timer.getDelta());
		double renderStart = timer.getElapsedTime();

		MatrixStack viewMatrix;
		viewMatrix.push();
		viewMatrix.translate(0.0f, 0.0f, -3.0f);
		viewMatrix.rotateX(xAxisRotation);
		viewMatrix.rotateY(yAxisRotation);

		renderer.setCullState(CullStates::CullNone);
		renderer.setDepthTestState(DepthTestStates::LessThanOrEqual);
		
		colorShader.begin();
		colorShader.setUniform("projection", perspectiveMatrix);
		cube.pushTransform();
		cube.translate(0.0f, 0.0f, 0.0f);
		cube.scale(0.5f);

		// Render the geometry to be refracted, store result in rt
		refractionRT.begin();
		renderer.clearColorAndDepth();
		colorShader.setUniform("view", viewMatrix.top());
		cube.draw(GL_TRIANGLES);
		grid.draw(GL_LINES);
		refractionRT.end();

		// Render the geometry to be reflected, store result in rt
		reflectionRT.begin();
		renderer.clearColorAndDepth();
		viewMatrix.push();
		viewMatrix.scale(1.0f, -1.0f, 1.0f); // Reflect about xz-plane
		colorShader.setUniform("view", viewMatrix.top());
		cube.draw(GL_TRIANGLES);
		viewMatrix.pop();
		reflectionRT.end();

		colorShader.end();
		cube.popTransform();

		// Render the water with the previous reflection/refraction texture
		waterShader.begin();
		waterShader.setUniform("time", time);
		glActiveTexture(GL_TEXTURE0 + 0);
		refractionRT.bindTexture();
		glActiveTexture(GL_TEXTURE0 + 1);
		reflectionRT.bindTexture();
		glActiveTexture(GL_TEXTURE0 + 2);
		waterNormals.bind();
		//waterShader.setUniform("view", viewMatrix.top());
		waterShader.setUniform("refraction_tex", 0);
		waterShader.setUniform("reflection_tex", 1);
		waterShader.setUniform("water_normals_tex", 2);
		//waterShader.setUniform("light0_pos", vec3(0.0f, 1.0f, 0.0f));
		//waterShader.setUniform("light0_col", vec3(1.0f, 0.8f, 0.5f));
		//waterShader.setUniform("ambient", vec3(67.0f/255.0f, 66.0f/255.0f, 63.0f/255.0f));
		quadVbo.bind();
		waterShader.setAttributefv("position", 2, 4, 0);
		waterShader.setAttributefv("texel", 2, 4, 2);
		glDrawArrays(GL_TRIANGLES, 0, 6);
		quadVbo.unbind();
		reflectionRT.unbindTexture();
		refractionRT.unbindTexture();
		waterNormals.unbind();
		waterShader.end();
		glActiveTexture(GL_TEXTURE0 + 0);

		// Render unmirrored scene
		//colorShader.begin();
		//renderer.clearColorAndDepth();
		//renderer.setCullState(CullStates::CullNone);
		//renderer.setBlendState(BlendStates::AlphaBlend);
		//renderer.setDepthTestState(DepthTestStates::LessThanOrEqual);
		//colorShader.setUniform("projection", perspectiveMatrix);
		//colorShader.setUniform("view", viewMatrix.top());
		//cube.pushTransform();
		//cube.translate(0.0f, 0.4f, 0.0f);
		//cube.scale(0.5f);
		//cube.draw(GL_TRIANGLES);

		/*grid.pushTransform();
		grid.translate(0.0f, -0.5f, 0.0f);
		grid.draw(GL_LINES);
		grid.popTransform();*/

		// Draw mirrored scene to a rendertarget
		/*rt.begin();
		renderer.clearColorAndDepth();
		
		viewMatrix.push();
		viewMatrix.scale(1.0f, -1.0f, 1.0f);
		colorShader.setUniform("view", viewMatrix.top());
		cube.draw(GL_TRIANGLES);
		cube.popTransform();
		viewMatrix.pop();
		rt.end();*/

		// Enable stencil testing and mask out a section containing the water mesh
		//glEnable(GL_STENCIL_TEST);
		//glStencilFunc(GL_ALWAYS, 1, 0xFF); // Set any stencil to 1
		//glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
		//glStencilMask(0xFF); // Write to stencil buffer
		//glDepthMask(GL_FALSE); // Don't write to depth buffer
		//glClear(GL_STENCIL_BUFFER_BIT); // Clear stencil buffer (0 by default)

		//// Draw water mesh
		//water.pushTransform();
		//water.scale(3.0f);
		//water.draw(GL_TRIANGLES);
		//water.popTransform();
		//colorShader.end();

		//// Draw previous rendertarget as a quad masked into the water plane
		//glStencilFunc(GL_EQUAL, 1, 0xFF); // Pass test if stencil value is 1
		//glStencilMask(0x00); // Don't write anything to stencil buffer
		//glDepthMask(GL_TRUE);

		//glDisable(GL_STENCIL_TEST);

		viewMatrix.pop();

		context.display();
		renderTime = timer.getElapsedTime() - renderStart;
		if(renderTime < 0.013)
			context.sleep(0.013 - renderTime);

		if(checkGLErrors(std::cerr))
		{
			std::cin.get();
			context.close();
		}
	}

	waterNormals.dispose();
	colorShader.dispose();
	waterShader.dispose();
	vao.dispose();
	context.dispose();
}
Example #5
0
int main(int argc, char** argv)
{
    SDL_Window* window;
    SDL_GLContext ctx;
    GLuint vao;

    if(!initSDL(&window, &ctx) || !initGLEW())
    {
        return false;
    }

    // Create camera
    Camera camera(glm::radians(60.0f),
                  static_cast<float>(width)/static_cast<float>(height),
                  0.000001f,
                  1000.0f);
    camera.getTransform()->setPosition(0.0f,0.0f,5.0f);

    VertexShader vs;
    FragmentShader fs;
    ShaderProgram shaderProg;

    WavefrontMeshFactory factory;
    Mesh* mesh = factory.load("../../wreck/assets/uvcube.obj");
    if(!vs.load("../../wreck/assets/lambert.vs")) std::cout << "Vertex Shader error." << std::endl;
    if(!fs.load("../../wreck/assets/lambert.fs")) std::cout << "Fragment shader error." << std::endl;

    Texture texture;
    texture.load("../../wreck/assets/uvpattern.dds");

    Light light(glm::vec3(5.0f, 5.0f, 5.0f), glm::vec3(1.0f, 1.0f, 1.0f));
    light.setIntensity(1.0f);

    std::cout << "Linking..." << std::endl;
    shaderProg.setVertexShader(&vs);
    shaderProg.setFragmentShader(&fs);
    shaderProg.link();

    //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
    glEnable(GL_DEPTH_TEST);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Black

    Uint32 ticks = SDL_GetTicks();
    bool running = true;
    while(running)
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        SDL_Event event;
        while(SDL_PollEvent(&event))
        {
            Uint32 elapsed = SDL_GetTicks()-ticks;
            ticks = SDL_GetTicks();

            switch (event.type)
            {
            case SDL_KEYDOWN:
                keyboardCameraControl(event, camera, elapsed);
                break;
            case SDL_KEYUP:
                // if escape is pressed, quit
                if (event.key.keysym.sym == SDLK_ESCAPE)
                    running = false; // set status to 1 to exit main loop
                break;
            case SDL_MOUSEMOTION:
                mouseCameraControl(event, window, camera, elapsed);
                break;
            case SDL_QUIT:
                running = false;
                break;
            }
        }

        glm::vec3 lightPos = light.getTransform()->getPosition();
        glm::vec3 lightColor = light.getColor() * light.getIntensity();
        glm::vec4 diffuse = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
        glm::mat4 m = glm::mat4(1.0f);
        glm::mat4 v = camera.getViewMatrix();
        glm::mat4 p = camera.getProjectionMatrix();
        glm::mat4 mvp = p*v*m;


        // Begin drawing
        shaderProg.begin();
            mesh->use();
            texture.use();

            shaderProg.setUniformValue(0, mvp);
            shaderProg.setUniformValue(1, m);
            shaderProg.setUniformValue(2, v);
            shaderProg.setUniformValue(3, lightPos);
            shaderProg.setUniformValue(4, lightColor);
            //shaderProg.setUniformValue(1, diffuse);
            glDrawElements(GL_TRIANGLES, mesh->indices.size(), GL_UNSIGNED_INT, 0);
        shaderProg.end();

        SDL_GL_SwapWindow(window);
    }

    SDL_GL_DeleteContext(ctx);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}
	bool onFrame(){

		gl.clearColor(0.1, 0.1, 0.1, 1);
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
		gl.viewport(0,0, width(), height());

		gl.matrixMode(gl.PROJECTION);
		gl.loadMatrix(Matrix4d::perspective(45, aspect(), 0.1, 100));

		gl.matrixMode(gl.MODELVIEW);
		gl.loadMatrix(Matrix4d::lookAt(Vec3d(0,0,4), Vec3d(0,0,0), Vec3d(0,1,0)));


		gl.disable(gl.LIGHTING);

//		shaderprogram.begin();
//		shaderprogram.uniform("tex0", 0);
//		GraphicsGL::gl_error("shader");
//		tex.bind(0);
//		gl.begin(gl.QUADS);
//		gl.color(1, 1, 1);
//		gl.texCoord(0, 0);
//		gl.vertex(0, 0, 0);
//		gl.texCoord(0, 1);
//		gl.vertex(0, 1, 0);
//		gl.texCoord(1, 1);
//		gl.vertex(1, 1, 0);
//		gl.texCoord(1, 0);
//		gl.vertex(1, 0, 0);
//		gl.end();
//		tex.unbind(0);
//		shaderprogram.end();


		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);    // Uses default lighting parameters
		glEnable(GL_DEPTH_TEST);
		glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
		glEnable(GL_NORMALIZE);
		glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);

		const GLfloat pos[]={ 1.f, 1.f, 2.f, 0.f };
		glLightfv(GL_LIGHT0, GL_POSITION, pos);

//		gl.enable(gl.DEPTH_TEST);
////		gl.enable(gl.NORMALIZE);
//		light.twoSided(true);
//		light.dir(1.f, 1.f, 2.f);
//
//		light();
//		material();
//		glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);

		gl.pushMatrix();

		// rotate it around the y axis
		gl.rotate(a, 0.f,1.f,0.f);
		a += 0.5;

		// scale the whole asset to fit into our view frustum
		float tmp = scene_max[0]-scene_min[0];
		tmp = al::max(scene_max[1] - scene_min[1],tmp);
		tmp = al::max(scene_max[2] - scene_min[2],tmp);
		tmp = 2.f / tmp;
		gl.scale(tmp);

		// center the model
		gl.translate( -scene_center );



		shaderprogram.begin();
		shaderprogram.uniform("tex0", 1);
		Graphics::error("tex0");
			tex.bind(1);
				scene_list.draw();
			tex.unbind(1);
		shaderprogram.end();

		gl.popMatrix();

		return true;
	}
Example #7
0
void ModelRendererGl::renderMesh(const Mesh *mesh, float fade, int frame, int id, ShaderProgram *customShaders) {
	//assertions
	assertGl();

	const RenderMode &mode = m_renderMode;
	if (mode == RenderMode::SELECTION && mesh->isNoSelect()) {
		return;
	}

	bool renderTextures = (mode == RenderMode::UNITS || mode == RenderMode::OBJECTS || mode == RenderMode::SHADOWS);
	bool sendNormals = (mode == RenderMode::UNITS || mode == RenderMode::OBJECTS);

	// set cull face
	if (mesh->isTwoSided()) {
		glDisable(GL_CULL_FACE);
	} else {
		glEnable(GL_CULL_FACE);
	}

	// mesh colour (units only, tileset objects use colour set by engine based on FoW tex)
	if (m_renderMode == RenderMode::UNITS) {
		Vec4f color(mesh->getDiffuseColor(), std::min(mesh->getOpacity(), fade));
		glColor4fv(color.ptr());
	}

	const Texture2DGl *texture = 0, *textureNormal = 0, *textureCustom = 0;

	// diffuse texture
	glActiveTexture(diffuseTextureUnit);
	texture = static_cast<const Texture2DGl*>(mesh->getTexture(MeshTexture::DIFFUSE));
	if (texture != NULL && renderTextures) {
		if (m_lastTexture != texture->getHandle()) {
			assert(glIsTexture(texture->getHandle()));
			glBindTexture(GL_TEXTURE_2D, texture->getHandle());
			m_lastTexture = texture->getHandle();
		}
	} else {
		glBindTexture(GL_TEXTURE_2D, 0);
		m_lastTexture = 0;
	}
	
	// bump map
	textureNormal = static_cast<const Texture2DGl*>(mesh->getTexture(MeshTexture::NORMAL));
	glActiveTexture(normalTextureUnit);
	if (textureNormal != NULL && sendNormals) {
		assert(glIsTexture(textureNormal->getHandle()));
		glBindTexture(GL_TEXTURE_2D, textureNormal->getHandle());
	} else {
		glBindTexture(GL_TEXTURE_2D, 0);
		glDisable(GL_TEXTURE_2D);
	}

	// custom map
	if (customShaders && renderTextures) {
		textureCustom = static_cast<const Texture2DGl*>(mesh->getTexture(MeshTexture::CUSTOM));
		glActiveTexture(customTextureUnit);
		if (textureCustom) {
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, textureCustom->getHandle());
		} else {
			glDisable(GL_TEXTURE_2D);
		}
	}
	glActiveTexture(diffuseTextureUnit);

	//misc vars
	uint32 vertexCount = mesh->getVertexCount();
	uint32 indexCount = mesh->getIndexCount();

	//assertions
	assertGl();

	if (!vertexCount) {
		return;
	}

	ShaderProgram *shaderProgram;
	if (m_shaderIndex == -1 || mode == RenderMode::SELECTION || mode == RenderMode::SHADOWS) {
		shaderProgram = m_fixedFunctionProgram;
		if (m_meshCallback) {
			m_meshCallback->execute(mesh);
		}
	} else {
		if (customShaders) {
			shaderProgram = customShaders;
		} else {
			shaderProgram = m_shaders[m_shaderIndex];
		}
	}
	if (shaderProgram != m_lastShaderProgram) {
		if (m_lastShaderProgram) {
			m_lastShaderProgram->end();
		}
		shaderProgram->begin();
		shaderProgram->setUniform("gae_IsUsingFog", GLuint(m_useFog));
		m_lastShaderProgram = shaderProgram;
	}
	///@todo would be better to do this once only per faction, set from the game somewhere/somehow
	shaderProgram->setUniform("gae_TeamColour", getTeamColour());
	int teamColourFlag = (mesh->usesTeamTexture() && mode == RenderMode::UNITS) ? 1 : 0;
	shaderProgram->setUniform("gae_UsesTeamColour", teamColourFlag);
	shaderProgram->setUniform("gae_AlphaThreshold", m_alphaThreshold);
	shaderProgram->setUniform("gae_LightCount", m_currentLightCount);
	if (customShaders) {
		shaderProgram->setUniform("gae_FrameNumber", frame);
		shaderProgram->setUniform("gae_EntityId", id);
	}

	// vertices
	const MeshVertexBlock *mainBlock = 0;
	const MeshVertexBlock &staticBlock = mesh->getStaticVertData();
	if (staticBlock.count != 0) {
		mainBlock = &staticBlock;
	} else {
		mainBlock = &mesh->getInterpolationData()->getVertexBlock();
	}
	const int stride = mainBlock->getStride();
	int tanAttribLoc = -1;
	if (mainBlock->vbo_handle) {
#		define VBO_OFFSET(x) ((void*)(x * sizeof(float)))
		glBindBuffer(GL_ARRAY_BUFFER, mainBlock->vbo_handle);
		glVertexPointer(3, GL_FLOAT, stride, VBO_OFFSET(0));
		if (sendNormals) {
			glNormalPointer(GL_FLOAT, stride, VBO_OFFSET(3));
		}
		if (sendNormals && textureNormal
		&& (mainBlock->type == MeshVertexBlock::POS_NORM_TAN 
		|| mainBlock->type == MeshVertexBlock::POS_NORM_TAN_UV)) {
			shaderProgram->setUniform("gae_HasNormalMap", 1u);
			tanAttribLoc = shaderProgram->getAttribLoc("gae_Tangent");
			if (tanAttribLoc != -1) {
				glEnableVertexAttribArray(tanAttribLoc);
				glVertexAttribPointer(tanAttribLoc, 3, GL_FLOAT, GL_TRUE, stride, VBO_OFFSET(6));
			}
		} else {
			shaderProgram->setUniform("gae_HasNormalMap", 0u);
		}
		if (renderTextures && mesh->getTexture(MeshTexture::DIFFUSE)) {
			int uvOffset = mainBlock->getUvOffset();
			if (uvOffset != -1) {
				if (m_duplicateTexCoords) {
					glActiveTexture(GL_TEXTURE0 + m_secondaryTexCoordUnit);
					glEnableClientState(GL_TEXTURE_COORD_ARRAY);
					glTexCoordPointer(2, GL_FLOAT, stride, VBO_OFFSET(uvOffset));
				}
				glActiveTexture(GL_TEXTURE0);
				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
				glTexCoordPointer(2, GL_FLOAT, stride, VBO_OFFSET(uvOffset));
			} else {
				const MeshVertexBlock &uvBlock = mesh->getTecCoordBlock();
				assert(uvBlock.count != 0);
				glBindBuffer(GL_ARRAY_BUFFER, uvBlock.vbo_handle);
				if (m_duplicateTexCoords) {
					glActiveTexture(GL_TEXTURE0 + m_secondaryTexCoordUnit);
					glEnableClientState(GL_TEXTURE_COORD_ARRAY);
					glTexCoordPointer(2, GL_FLOAT, 0, VBO_OFFSET(0));
				}
				glActiveTexture(GL_TEXTURE0);
				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
				glTexCoordPointer(2, GL_FLOAT, 0, VBO_OFFSET(0));
			} 
		} else {
			if (m_duplicateTexCoords) {
				glActiveTexture(GL_TEXTURE0 + m_secondaryTexCoordUnit);
				glDisableClientState(GL_TEXTURE_COORD_ARRAY);
			}
			glActiveTexture(GL_TEXTURE0);
			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		}
		assertGl();
		// draw model
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getIndices().vbo_handle);
		int indexType = mesh->getIndices().type == MeshIndexBlock::UNSIGNED_16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
		glDrawRangeElements(GL_TRIANGLES, 0, vertexCount-1, indexCount, indexType, VBO_OFFSET(0));

		glBindBuffer(GL_ARRAY_BUFFER, 0);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
		if (tanAttribLoc != -1) {
			glDisableVertexAttribArray(tanAttribLoc);
		}

		assertGl();

	} else { // Non static mesh or VBOs disabled
		glVertexPointer(3, GL_FLOAT, stride, mainBlock->m_arrayPtr);
		if (sendNormals) {
			glNormalPointer(GL_FLOAT, stride, &mainBlock->m_posNorm[0].norm);
		}
		if (sendNormals && textureNormal
		&& (mainBlock->type == MeshVertexBlock::POS_NORM_TAN 
		|| mainBlock->type == MeshVertexBlock::POS_NORM_TAN_UV)) {
			shaderProgram->setUniform("gae_HasNormalMap", 1u);
			tanAttribLoc = shaderProgram->getAttribLoc("gae_Tangent");
			if (tanAttribLoc != -1) {
				glEnableVertexAttribArray(tanAttribLoc);
				glVertexAttribPointer(tanAttribLoc, 3, GL_FLOAT, GL_TRUE, stride, &mainBlock->m_posNormTan[0].tan);
			}
		} else {
			shaderProgram->setUniform("gae_HasNormalMap", 0u);
		}
		if (renderTextures && mesh->getTexture(MeshTexture::DIFFUSE)) {
			int uvOffset = mainBlock->getUvOffset();
			if (uvOffset != -1) {
				if (m_duplicateTexCoords) {
					glActiveTexture(GL_TEXTURE0 + m_secondaryTexCoordUnit);
					glEnableClientState(GL_TEXTURE_COORD_ARRAY);
					glTexCoordPointer(2, GL_FLOAT, stride, &((float*)mainBlock->m_arrayPtr)[uvOffset]);
				}
				glActiveTexture(GL_TEXTURE0);
				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
				glTexCoordPointer(2, GL_FLOAT, stride, &((float*)mainBlock->m_arrayPtr)[uvOffset]);
			} else {
				const MeshVertexBlock &uvBlock = mesh->getTecCoordBlock();
				assert(uvBlock.count != 0);
				if (uvBlock.vbo_handle) {
					glBindBuffer(GL_ARRAY_BUFFER, uvBlock.vbo_handle);
				}
				if (m_duplicateTexCoords) {
					glActiveTexture(GL_TEXTURE0 + m_secondaryTexCoordUnit);
					glEnableClientState(GL_TEXTURE_COORD_ARRAY);
					if (uvBlock.vbo_handle) {
						glTexCoordPointer(2, GL_FLOAT, 0, VBO_OFFSET(0));
					} else {
						glTexCoordPointer(2, GL_FLOAT, 0, uvBlock.m_arrayPtr);
					}
				}
				glActiveTexture(GL_TEXTURE0);
				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
				if (uvBlock.vbo_handle) {
					glTexCoordPointer(2, GL_FLOAT, 0, VBO_OFFSET(0));
				} else {
					glTexCoordPointer(2, GL_FLOAT, 0, uvBlock.m_arrayPtr);
				}
			} 
		} else {
			if (m_duplicateTexCoords) {
				glActiveTexture(GL_TEXTURE0 + m_secondaryTexCoordUnit);
				glDisableClientState(GL_TEXTURE_COORD_ARRAY);
			}
			glActiveTexture(GL_TEXTURE0);
			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		}
		int indexType = mesh->getIndices().type == MeshIndexBlock::UNSIGNED_16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;

		if (use_vbos) {
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getIndices().vbo_handle);
			glDrawRangeElements(GL_TRIANGLES, 0, vertexCount-1, indexCount, indexType, VBO_OFFSET(0));
			glBindBuffer(GL_ARRAY_BUFFER, 0);
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
		} else {
			glDrawRangeElements(GL_TRIANGLES, 0, vertexCount-1, indexCount, indexType, mesh->getIndices().m_indices);
		}
		if (tanAttribLoc != -1) {
			glDisableVertexAttribArray(tanAttribLoc);
		}
	}
	assertGl();
}