Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
27 views5 pages

Rasterize

This document contains a minimal OpenGL program that implements a CPU-based software rasterizer to draw triangles and display them as textures. It includes functions for framebuffer management, pixel manipulation, and triangle rasterization using barycentric coordinates. The program initializes OpenGL, creates a test triangle, and continuously renders it in a window until closed.

Uploaded by

Lin Toni
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views5 pages

Rasterize

This document contains a minimal OpenGL program that implements a CPU-based software rasterizer to draw triangles and display them as textures. It includes functions for framebuffer management, pixel manipulation, and triangle rasterization using barycentric coordinates. The program initializes OpenGL, creates a test triangle, and continuously renders it in a window until closed.

Uploaded by

Lin Toni
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 5

// software_rasterizer.

cpp
// A minimal OpenGL program that implements a custom CPU-based software rasterizer
// and uses OpenGL to display the resulting framebuffer as a texture.

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <vector>
#include <cmath>
#include <cstdint>
#include <algorithm> // for std::min, std::max (optional)

// Window dimensions
constexpr int WIDTH = 800;
constexpr int HEIGHT = 600;

// Vertex with position and color


struct Vertex {
glm::vec2 pos;
glm::u8vec3 color;
};

// Framebuffer as an array of RGB pixels


static std::vector<uint8_t> framebuffer(WIDTH* HEIGHT * 3);

// Clear framebuffer to black


static void clearFramebuffer() {
std::fill(framebuffer.begin(), framebuffer.end(), 0);
}

// Put a pixel with clamping


static void putPixel(int x, int y, const glm::u8vec3& color) {
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) return;
int idx = (y * WIDTH + x) * 3;
framebuffer[idx + 0] = color.r;
framebuffer[idx + 1] = color.g;
framebuffer[idx + 2] = color.b;
}

// Compute barycentric coordinates for point p with respect to triangle (a, b, c)


static bool barycentric(const glm::vec2& p,
const glm::vec2& a,
const glm::vec2& b,
const glm::vec2& c,
float& u, float& v, float& w) {
float denom = (b.y - c.y) * (a.x - c.x) + (c.x - b.x) * (a.y - c.y);
if (std::fabs(denom) < 1e-6f) return false;
u = ((b.y - c.y) * (p.x - c.x) + (c.x - b.x) * (p.y - c.y)) / denom;
v = ((c.y - a.y) * (p.x - c.x) + (a.x - c.x) * (p.y - c.y)) / denom;
w = 1.0f - u - v;
return u >= 0.f && v >= 0.f && w >= 0.f;
}

// Draw a filled triangle


static void drawTriangle(const Vertex& v0, const Vertex& v1, const Vertex& v2) {
// Compute bounding box in screen space
int minX = static_cast<int>(std::floor(std::min({ v0.pos.x, v1.pos.x,
v2.pos.x })));
int maxX = static_cast<int>(std::ceil(std::max({ v0.pos.x, v1.pos.x,
v2.pos.x })));
int minY = static_cast<int>(std::floor(std::min({ v0.pos.y, v1.pos.y,
v2.pos.y })));
int maxY = static_cast<int>(std::ceil(std::max({ v0.pos.y, v1.pos.y,
v2.pos.y })));

// Clip to screen using glm::clamp


minX = glm::clamp(minX, 0, WIDTH - 1);
maxX = glm::clamp(maxX, 0, WIDTH - 1);
minY = glm::clamp(minY, 0, HEIGHT - 1);
maxY = glm::clamp(maxY, 0, HEIGHT - 1);

// Rasterize
for (int y = minY; y <= maxY; ++y) {
for (int x = minX; x <= maxX; ++x) {
glm::vec2 p{ x + 0.5f, y + 0.5f };
float u, v, w;
if (barycentric(p, v0.pos, v1.pos, v2.pos, u, v, w)) {
glm::u8vec3 col(
static_cast<uint8_t>(u * v0.color.r + v * v1.color.r + w *
v2.color.r),
static_cast<uint8_t>(u * v0.color.g + v * v1.color.g + w *
v2.color.g),
static_cast<uint8_t>(u * v0.color.b + v * v1.color.b + w *
v2.color.b)
);
putPixel(x, y, col);
}
}
}
}

// Create a test triangle


static std::vector<Vertex> createTestTriangle() {
return {
{{100.0f, 100.0f}, {255, 0, 0}}, // Red
{{700.0f, 150.0f}, { 0, 255, 0}}, // Green
{{400.0f, 500.0f}, { 0, 0, 255}} // Blue
};
}

// Fullscreen quad for displaying texture


static float quadVerts[] = {
// positions // uvs
-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, 0.0f, 1.0f
};
static unsigned int quadIdx[] = { 0,1,2, 2,3,0 };

// Shader sources
const char* vsSource = R"(
#version 330 core
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inUV;
out vec2 fragUV;
void main() {
fragUV = inUV;
gl_Position = vec4(inPos, 0.0, 1.0);
}
)";

const char* fsSource = R"(


#version 330 core
in vec2 fragUV;
out vec4 outColor;
uniform sampler2D tex;
void main() {
outColor = texture(tex, fragUV);
}
)";

// Compile shader utility


static GLuint compileShader(GLenum type, const char* src) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);
int success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char log[512];
glGetShaderInfoLog(shader, 512, nullptr, log);
std::cerr << "Shader compile error: " << log << std::endl;
}
return shader;
}

int main() {
// Init GLFW
if (!glfwInit()) return -1;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Software Rasterizer",


nullptr, nullptr);
if (!window) { glfwTerminate(); return -1; }
glfwMakeContextCurrent(window);

// Init GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cerr << "Failed to initialize GLAD\n";
return -1;
}

// Create texture for framebuffer


GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB,
GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Setup quad VAO/VBO
GLuint vao, vbo, ebo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);

glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVerts), quadVerts, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quadIdx), quadIdx,
GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 *
sizeof(float)));

// Compile shaders and link program


GLuint vs = compileShader(GL_VERTEX_SHADER, vsSource);
GLuint fs = compileShader(GL_FRAGMENT_SHADER, fsSource);
GLuint prog = glCreateProgram();
glAttachShader(prog, vs);
glAttachShader(prog, fs);
glLinkProgram(prog);
glUseProgram(prog);
glUniform1i(glGetUniformLocation(prog, "tex"), 0);

// Main loop
while (!glfwWindowShouldClose(window)) {
// Rasterize scene
clearFramebuffer();
auto tri = createTestTriangle();
drawTriangle(tri[0], tri[1], tri[2]);

// Upload framebuffer to texture


glBindTexture(GL_TEXTURE_2D, tex);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT, GL_RGB,
GL_UNSIGNED_BYTE, framebuffer.data());

// Render quad
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);

glfwSwapBuffers(window);
glfwPollEvents();
}

// Cleanup
glDeleteProgram(prog);
glDeleteShader(vs);
glDeleteShader(fs);
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ebo);
glDeleteVertexArrays(1, &vao);
glDeleteTextures(1, &tex);
glfwTerminate();
return 0;
}

You might also like