From cbfa82f5be08ed05927fb5d4d73a178c18c879e7 Mon Sep 17 00:00:00 2001 From: CJSatnarine Date: Wed, 26 Feb 2025 16:07:08 -0500 Subject: [PATCH] added code --- CMakeLists.txt | 4 +- src/main.cpp | 13 ++ src/tgaimage.cpp | 352 +++++++++++++++++++++++++++++++++++++++++++++++ src/tgaimage.h | 96 +++++++++++++ 4 files changed, 464 insertions(+), 1 deletion(-) create mode 100644 src/main.cpp create mode 100644 src/tgaimage.cpp create mode 100644 src/tgaimage.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f4387ea..cbfdb47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,5 +2,7 @@ cmake_minimum_required(VERSION 3.5.0) project(tiny_renderer VERSION 0.1.0 LANGUAGES C CXX) add_executable(tiny_renderer - + src/main.cpp + src/tgaimage.cpp + src/tgaimage.h ) diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..2fba26a --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,13 @@ +#include "tgaimage.h" + +const TGAColor white = TGAColor(255, 255, 255, 255); +const TGAColor red = TGAColor(255, 0, 0, 255); + +int main(int argc, char** argv) { + TGAImage image(100, 100, TGAImage::RGB); + image.set(52, 41, red); + image.flip_vertically(); // i want to have the origin at the left bottom corner of the image + image.write_tga_file("output.tga"); + return 0; +} + diff --git a/src/tgaimage.cpp b/src/tgaimage.cpp new file mode 100644 index 0000000..12eef1c --- /dev/null +++ b/src/tgaimage.cpp @@ -0,0 +1,352 @@ +#include +#include +#include +#include +#include +#include "tgaimage.h" + +TGAImage::TGAImage() : data(NULL), width(0), height(0), bytespp(0) { +} + +TGAImage::TGAImage(int w, int h, int bpp) : data(NULL), width(w), height(h), bytespp(bpp) { + unsigned long nbytes = width*height*bytespp; + data = new unsigned char[nbytes]; + memset(data, 0, nbytes); +} + +TGAImage::TGAImage(const TGAImage &img) { + width = img.width; + height = img.height; + bytespp = img.bytespp; + unsigned long nbytes = width*height*bytespp; + data = new unsigned char[nbytes]; + memcpy(data, img.data, nbytes); +} + +TGAImage::~TGAImage() { + if (data) delete [] data; +} + +TGAImage & TGAImage::operator =(const TGAImage &img) { + if (this != &img) { + if (data) delete [] data; + width = img.width; + height = img.height; + bytespp = img.bytespp; + unsigned long nbytes = width*height*bytespp; + data = new unsigned char[nbytes]; + memcpy(data, img.data, nbytes); + } + return *this; +} + +bool TGAImage::read_tga_file(const char *filename) { + if (data) delete [] data; + data = NULL; + std::ifstream in; + in.open (filename, std::ios::binary); + if (!in.is_open()) { + std::cerr << "can't open file " << filename << "\n"; + in.close(); + return false; + } + TGA_Header header; + in.read((char *)&header, sizeof(header)); + if (!in.good()) { + in.close(); + std::cerr << "an error occured while reading the header\n"; + return false; + } + width = header.width; + height = header.height; + bytespp = header.bitsperpixel>>3; + if (width<=0 || height<=0 || (bytespp!=GRAYSCALE && bytespp!=RGB && bytespp!=RGBA)) { + in.close(); + std::cerr << "bad bpp (or width/height) value\n"; + return false; + } + unsigned long nbytes = bytespp*width*height; + data = new unsigned char[nbytes]; + if (3==header.datatypecode || 2==header.datatypecode) { + in.read((char *)data, nbytes); + if (!in.good()) { + in.close(); + std::cerr << "an error occured while reading the data\n"; + return false; + } + } else if (10==header.datatypecode||11==header.datatypecode) { + if (!load_rle_data(in)) { + in.close(); + std::cerr << "an error occured while reading the data\n"; + return false; + } + } else { + in.close(); + std::cerr << "unknown file format " << (int)header.datatypecode << "\n"; + return false; + } + if (!(header.imagedescriptor & 0x20)) { + flip_vertically(); + } + if (header.imagedescriptor & 0x10) { + flip_horizontally(); + } + std::cerr << width << "x" << height << "/" << bytespp*8 << "\n"; + in.close(); + return true; +} + +bool TGAImage::load_rle_data(std::ifstream &in) { + unsigned long pixelcount = width*height; + unsigned long currentpixel = 0; + unsigned long currentbyte = 0; + TGAColor colorbuffer; + do { + unsigned char chunkheader = 0; + chunkheader = in.get(); + if (!in.good()) { + std::cerr << "an error occured while reading the data\n"; + return false; + } + if (chunkheader<128) { + chunkheader++; + for (int i=0; ipixelcount) { + std::cerr << "Too many pixels read\n"; + return false; + } + } + } else { + chunkheader -= 127; + in.read((char *)colorbuffer.raw, bytespp); + if (!in.good()) { + std::cerr << "an error occured while reading the header\n"; + return false; + } + for (int i=0; ipixelcount) { + std::cerr << "Too many pixels read\n"; + return false; + } + } + } + } while (currentpixel < pixelcount); + return true; +} + +bool TGAImage::write_tga_file(const char *filename, bool rle) { + unsigned char developer_area_ref[4] = {0, 0, 0, 0}; + unsigned char extension_area_ref[4] = {0, 0, 0, 0}; + unsigned char footer[18] = {'T','R','U','E','V','I','S','I','O','N','-','X','F','I','L','E','.','\0'}; + std::ofstream out; + out.open (filename, std::ios::binary); + if (!out.is_open()) { + std::cerr << "can't open file " << filename << "\n"; + out.close(); + return false; + } + TGA_Header header; + memset((void *)&header, 0, sizeof(header)); + header.bitsperpixel = bytespp<<3; + header.width = width; + header.height = height; + header.datatypecode = (bytespp==GRAYSCALE?(rle?11:3):(rle?10:2)); + header.imagedescriptor = 0x20; // top-left origin + out.write((char *)&header, sizeof(header)); + if (!out.good()) { + out.close(); + std::cerr << "can't dump the tga file\n"; + return false; + } + if (!rle) { + out.write((char *)data, width*height*bytespp); + if (!out.good()) { + std::cerr << "can't unload raw data\n"; + out.close(); + return false; + } + } else { + if (!unload_rle_data(out)) { + out.close(); + std::cerr << "can't unload rle data\n"; + return false; + } + } + out.write((char *)developer_area_ref, sizeof(developer_area_ref)); + if (!out.good()) { + std::cerr << "can't dump the tga file\n"; + out.close(); + return false; + } + out.write((char *)extension_area_ref, sizeof(extension_area_ref)); + if (!out.good()) { + std::cerr << "can't dump the tga file\n"; + out.close(); + return false; + } + out.write((char *)footer, sizeof(footer)); + if (!out.good()) { + std::cerr << "can't dump the tga file\n"; + out.close(); + return false; + } + out.close(); + return true; +} + +// TODO: it is not necessary to break a raw chunk for two equal pixels (for the matter of the resulting size) +bool TGAImage::unload_rle_data(std::ofstream &out) { + const unsigned char max_chunk_length = 128; + unsigned long npixels = width*height; + unsigned long curpix = 0; + while (curpix=width || y>=height) { + return TGAColor(); + } + return TGAColor(data+(x+y*width)*bytespp, bytespp); +} + +bool TGAImage::set(int x, int y, TGAColor c) { + if (!data || x<0 || y<0 || x>=width || y>=height) { + return false; + } + memcpy(data+(x+y*width)*bytespp, c.raw, bytespp); + return true; +} + +int TGAImage::get_bytespp() { + return bytespp; +} + +int TGAImage::get_width() { + return width; +} + +int TGAImage::get_height() { + return height; +} + +bool TGAImage::flip_horizontally() { + if (!data) return false; + int half = width>>1; + for (int i=0; i>1; + for (int j=0; j=(int)width) { + errx -= width; + nx += bytespp; + memcpy(tdata+nscanline+nx, data+oscanline+ox, bytespp); + } + } + erry += h; + oscanline += olinebytes; + while (erry>=(int)height) { + if (erry>=(int)height<<1) // it means we jump over a scanline + memcpy(tdata+nscanline+nlinebytes, tdata+nscanline, nlinebytes); + erry -= height; + nscanline += nlinebytes; + } + } + delete [] data; + data = tdata; + width = w; + height = h; + return true; +} + diff --git a/src/tgaimage.h b/src/tgaimage.h new file mode 100644 index 0000000..7d5d9fb --- /dev/null +++ b/src/tgaimage.h @@ -0,0 +1,96 @@ +#ifndef __IMAGE_H__ +#define __IMAGE_H__ + +#include + +#pragma pack(push,1) +struct TGA_Header { + char idlength; + char colormaptype; + char datatypecode; + short colormaporigin; + short colormaplength; + char colormapdepth; + short x_origin; + short y_origin; + short width; + short height; + char bitsperpixel; + char imagedescriptor; +}; +#pragma pack(pop) + + + +struct TGAColor { + union { + struct { + unsigned char b, g, r, a; + }; + unsigned char raw[4]; + unsigned int val; + }; + int bytespp; + + TGAColor() : val(0), bytespp(1) { + } + + TGAColor(unsigned char R, unsigned char G, unsigned char B, unsigned char A) : b(B), g(G), r(R), a(A), bytespp(4) { + } + + TGAColor(int v, int bpp) : val(v), bytespp(bpp) { + } + + TGAColor(const TGAColor &c) : val(c.val), bytespp(c.bytespp) { + } + + TGAColor(const unsigned char *p, int bpp) : val(0), bytespp(bpp) { + for (int i=0; i