Ejemplo n.º 1
0
SWR_FN void swr_render_model(swr_render_target *target, u32 render_mode, model *model, vec3 cam_pos,
                             mat4 model_mat, mat4 viewproj_mat, mat4 screen_mat, vec3 sun_direction,
                             col4 sun_col, float ambient_intencity, mem_pool *pool) {
	tex2d target_tex = *target->texture;
	float *z_buffer = target->z_buffer;

	u8 *old_hi_ptr = pool->hi;
	vec4 *vertices = (vec4 *)mem_push_back(pool, model->nvertices * sizeof(*vertices));
	vec3 *cam_directions = (vec3 *)mem_push_back(pool, model->nvertices * sizeof(*cam_directions));
	for (u32 i = 0, e = model->nvertices; i < e; ++i) {
		vec3 v = mul_m4v4(model_mat, v3_to_v4(model->vertices[i], 1.0f)).xyz;
		cam_directions[i] = norm_v3(sub_v3(v, cam_pos));
		vertices[i] = mul_m4v4(viewproj_mat, v3_to_v4(v, 1.0f));
	}

	face **culled_faces = (face **)mem_push_back(pool, model->nface_groups * sizeof(*culled_faces));
	u32 *nculled_faces = (u32 *)mem_push_back(pool, model->nface_groups * sizeof(*nculled_faces));

	for (u32 face_group = 0; face_group < model->nface_groups; ++face_group) {
		face *src_faces = model->face_groups[face_group].faces;
		u32 nsrc_faces = model->face_groups[face_group].nfaces;
		face *faces = culled_faces[face_group] =
		    (face *)mem_push_back(pool, nsrc_faces * sizeof(*faces));
		u32 nfaces = 0;
		for (u32 i = 0; i < nsrc_faces; ++i) {
			face face = src_faces[i];

			b32 inside_frustrum = true;
			for (u32 j = 0; j < 3; ++j) {
				vec4 vertex = vertices[face.v[j]];

				if (vertex.x > vertex.w || vertex.x < -vertex.w || vertex.y > vertex.w ||
				    vertex.y < -vertex.w || vertex.z > vertex.w || vertex.z < -vertex.w ||
				    vertex.w == 0) {
					inside_frustrum = false;
					break;
				}
			}

			if (inside_frustrum)
				faces[nfaces++] = face;
		}

		nculled_faces[face_group] = nfaces;
	}

	// TODO: avoid computing irrelevant data (?)
	for (u32 i = 0; i < model->nvertices; ++i) {
		vec4 vertex = vertices[i];
		vertex = div_v4f(vertex, vertex.w);
		vertex = mul_m4v4(screen_mat, vertex);
		vertices[i] = vertex;
	}

	for (u32 face_group = 0; face_group < model->nface_groups; ++face_group) {
		face *faces = culled_faces[face_group];
		u32 nfaces = nculled_faces[face_group];

		material *material = model->face_groups[face_group].material;
		for (u32 i = 0; i < nfaces; ++i) {
			face face = faces[i];
			vec4 verts[] = {vertices[face.v[0]], vertices[face.v[1]], vertices[face.v[2]]};

			u32 x1 = (u32)verts[0].x;
			u32 y1 = (u32)verts[0].y;
			u32 x2 = (u32)verts[1].x;
			u32 y2 = (u32)verts[1].y;
			u32 x3 = (u32)verts[2].x;
			u32 y3 = (u32)verts[2].y;

			if (render_mode & (SRM_SHADED | SRM_TEXTURED)) {
				u32 minX = minu(x1, minu(x2, x3));
				u32 minY = minu(y1, minu(y2, y3));
				u32 maxX = maxu(x1, maxu(x2, x3)) + 1;
				u32 maxY = maxu(y1, maxu(y2, y3)) + 1;

				vec3 norms[3];
				float lum[3];
				if (render_mode & SRM_SHADED) {
					// TODO: apply reverse transformations to normales
					norms[0] = model->normales[face.n[0]];
					norms[1] = model->normales[face.n[1]];
					norms[2] = model->normales[face.n[2]];

					float diffuse[3];
					for (u32 j = 0; j < 3; ++j)
						diffuse[j] = clamp(dot_v3(norms[j], sun_direction), 0, 1.0f);

					vec3 L = neg_v3(sun_direction);
					float specular[3] = {0};
					for (u32 j = 0; j < 3; ++j) {
						if (diffuse[j]) {
							vec3 V = cam_directions[face.v[j]];
							vec3 H = norm_v3(add_v3(V, L));
							specular[j] = (float)pow(dot_v3(H, norms[j]), 32);
						}
					}

					for (u32 j = 0; j < 3; ++j)
						lum[j] = ambient_intencity + diffuse[j] + specular[j];
				}

				vec2 face_uvs[3];
				face_uvs[0] = model->uvs[face.uv[0]];
				face_uvs[1] = model->uvs[face.uv[1]];
				face_uvs[2] = model->uvs[face.uv[2]];

				vec2 a = {(float)x1, (float)y1};
				vec2 b = {(float)x2, (float)y2};
				vec2 c = {(float)x3, (float)y3};

				vec2 v0 = sub_v2(b, a);
				vec2 v1 = sub_v2(c, a);

				for (u32 x = minX; x < maxX; ++x) {
					for (u32 y = minY; y < maxY; ++y) {
						// calculate barycentric coords...
						vec2 p = {(float)x, (float)y};
						vec2 v2 = sub_v2(p, a);

						float d00 = dot_v2(v0, v0);
						float d01 = dot_v2(v0, v1);
						float d11 = dot_v2(v1, v1);
						float d20 = dot_v2(v2, v0);
						float d21 = dot_v2(v2, v1);

						float denom = d00 * d11 - d01 * d01;

						float v = (d11 * d20 - d01 * d21) / denom;
						float w = (d00 * d21 - d01 * d20) / denom;
						float u = 1.0f - v - w;

						if (!(v >= -0.001 && w >= -0.001 && u >= -0.001))
							continue;

						u32 z_buff_idx = y * target_tex.width + x;
						float z = verts[1].z * v + verts[2].z * w + verts[0].z * u;
						if (z_buffer[z_buff_idx] > z) {
							float l = 1.0f;

							if (render_mode & SRM_SHADED) {
								l = lum[1] * v + lum[2] * w + lum[0] * u;
							}

							col4 texel = {255, 255, 255, 255};

							if ((render_mode & SRM_TEXTURED) && material->diffuse) {
								float tu =
								    face_uvs[1].x * v + face_uvs[2].x * w + face_uvs[0].x * u;
								float tv =
								    face_uvs[1].y * v + face_uvs[2].y * w + face_uvs[0].y * u;
								tu *= material->diffuse->width;
								tv *= material->diffuse->height;
								texel = *sample_t2d(*material->diffuse, (u32)tu, (u32)tv);
							}

							col4 fragment_col = { .e[3] = 255 };
							for (u32 j = 0; j < 3; ++j) {
								float cl = sun_col.e[j] * l / 255.0f;
								fragment_col.e[j] = (u8)clamp(texel.e[j] * cl, 0, 255.0f);
							}
							*sample_t2d(target_tex, x, y) = fragment_col;
							z_buffer[z_buff_idx] = z;
						}
					}
				}
			}
		}

		if (render_mode & SRM_WIREFRAME) {
			for (u32 i = 0; i < nfaces; ++i) {
				const col4 model_col = {255, 255, 255, 255};

				vec4 v1 = vertices[faces[i].v[0]];
				vec4 v2 = vertices[faces[i].v[1]];
				vec4 v3 = vertices[faces[i].v[2]];

				s32 x1 = (s32)v1.x;
				s32 y1 = (s32)v1.y;
				s32 x2 = (s32)v2.x;
				s32 y2 = (s32)v2.y;
				s32 x3 = (s32)v3.x;
				s32 y3 = (s32)v3.y;

				swr_line(x1, y1, x2, y2, model_col, target_tex);
				swr_line(x2, y2, x3, y3, model_col, target_tex);
				swr_line(x3, y3, x1, y1, model_col, target_tex);
			}
		}
	}
Ejemplo n.º 2
0
int main(void)
{
	if(!glfwInit()) {
		printf("Could not init GLFW");
		getchar();
		return -1;
	}

	glfwWindowHint(GLFW_SAMPLES, 4);
	//Opengl 2.1
	//glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
	//glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
	//Opengl 3.3
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // MacOS fix
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	if(window_init(&window, 640, 480, "Test")) {
		fprintf( stderr, "Failed to open window.\n" );
		getchar();
		glfwTerminate();
	};

	window_set_size_callback(&window, window_size_callback);


	glewExperimental = GL_TRUE; // Needed for core profile
	if (glewInit() != GLEW_OK) {
		fprintf(stderr, "Failed to initialize GLEW\n");
		getchar();
		glfwTerminate();
		return -1;
	}
	//#clear errors GLEW may trigger
	printError();
	
	glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

	GLuint VertexArrayID;
	glGenVertexArrays(1, &VertexArrayID);
	glBindVertexArray(VertexArrayID);


	//Load model
	//----------

	Model cube;
	model_init(&cube);
	model_set_data_length(&cube, sizeof(cube_vertex_data));
	model_set_vertices(&cube, cube_vertex_data);
	model_set_colors(&cube, cube_color_data);
	model_set_uv_map(&cube, cube_uv_data);
	model_set_texture(&cube, "./textures/bricks.dds");
	model_bind(&cube);


	//Create shaders
	//--------------
	
	GLuint vertexShader, fragmentShader;

	loadShader(&vertexShader, GL_VERTEX_SHADER, mvpVertexShaderSource);
	loadShader(&fragmentShader, GL_FRAGMENT_SHADER, fragmentShaderSource);


	//Create program
	//--------------

	GLuint program;
	createProgram(&program, vertexShader, fragmentShader);


	// Enable z-buffer
	// ---------------

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);


	// Enable culling
	// --------------

	glEnable(GL_CULL_FACE);


	// Get MVP uniform
	// ---------------

	GLuint mvp_ul = glGetUniformLocation(program, "MVP");


	// Model Matrix
	// ------------

	Mat4 s;
	scale_m4(&s, 0.1f, 0.1f, 0.1f);
	printf("Scale:\n");
	print_m4(&s);

	Mat4 r;
	rotate_m4(&r, 0.0f, 1.0f, 0.0f, 0.0f);
	printf("Rotate:\n");
	print_m4(&r);

	Mat4 t;
	translate_m4(&t, 0.0f, 0.0f, 0.0f);
	printf("Translate:\n");
	print_m4(&t);

	Mat4 rs;
	printf("Rotated*Scaled:\n");
	mul_m4(&rs, &r, &s);
	print_m4(&rs);

	Mat4 model;
	printf("Model:\n");
	mul_m4(&model, &t, &rs);
	print_m4(&model);


	// Camera
	// ------

	Vec3 pos;
	Vec3 center;
	Vec3 up;
	Vec3 direction;
	Vec3 right;

	camera_init(&camera);
	camera_set_fov(&camera, 1.0f);
	camera_set_aspect(&camera, (float)window.width/(float)window.height);
	
	Input input;
	input_init(&input, &window, 0.5f, 0.5f, 0.8f, -5.7f, -2.7f);

	do {
		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

		glUseProgram(program);
		
		input_get_data(&input, &pos, &direction, &right);

		add_v3(&center, &pos, &direction);
		cross_v3(&up, &direction, &right);

		camera_set_position(&camera, &pos);
		camera_set_center(&camera, &center);
		camera_set_up(&camera, &up);


		// Mvp Matrix
		// ----------

		Mat4 vp;
		camera_get_matrix(&camera, &vp);

		Mat4 mvp;
		mul_m4(&mvp, &vp, &model);
		printf("Perspective:\n");
		print_m4(&mvp);


		// Set MVP transform
		glUniformMatrix4fv(mvp_ul, 1, GL_TRUE, &mvp[0][0]);

		model_render(&cube);

		window_swap_buffers(&window);
		glfwPollEvents();
	} while(
		glfwGetKey(window.handle, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
		glfwWindowShouldClose(window.handle) == 0
	);

	// Dispose
	// -------

	model_dispose(&cube);
	glDeleteVertexArrays(1, &VertexArrayID);
	glDetachShader(program, fragmentShader);
	glDetachShader(program, vertexShader);
	glDeleteShader(fragmentShader);
	glDeleteShader(vertexShader);
	glDeleteProgram(program);

	glfwTerminate();
	return 0;
}