添加项目文件。
							parent
							
								
									efad345b14
								
							
						
					
					
						commit
						02e5c3a599
					
				| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					# CMakeList.txt: 顶层 CMake 项目文件,在此处执行全局配置
 | 
				
			||||||
 | 
					# 并包含子项目。
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					cmake_minimum_required (VERSION 3.8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 如果支持,请为 MSVC 编译器启用热重载。
 | 
				
			||||||
 | 
					if (POLICY CMP0141)
 | 
				
			||||||
 | 
					  cmake_policy(SET CMP0141 NEW)
 | 
				
			||||||
 | 
					  set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					project ("tinyrender")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 包含子项目。
 | 
				
			||||||
 | 
					add_subdirectory ("tinyrender")
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,101 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "version": 3,
 | 
				
			||||||
 | 
					    "configurePresets": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "windows-base",
 | 
				
			||||||
 | 
					            "hidden": true,
 | 
				
			||||||
 | 
					            "generator": "Ninja",
 | 
				
			||||||
 | 
					            "binaryDir": "${sourceDir}/out/build/${presetName}",
 | 
				
			||||||
 | 
					            "installDir": "${sourceDir}/out/install/${presetName}",
 | 
				
			||||||
 | 
					            "cacheVariables": {
 | 
				
			||||||
 | 
					                "CMAKE_C_COMPILER": "cl.exe",
 | 
				
			||||||
 | 
					                "CMAKE_CXX_COMPILER": "cl.exe"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "condition": {
 | 
				
			||||||
 | 
					                "type": "equals",
 | 
				
			||||||
 | 
					                "lhs": "${hostSystemName}",
 | 
				
			||||||
 | 
					                "rhs": "Windows"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "x64-debug",
 | 
				
			||||||
 | 
					            "displayName": "x64 Debug",
 | 
				
			||||||
 | 
					            "inherits": "windows-base",
 | 
				
			||||||
 | 
					            "architecture": {
 | 
				
			||||||
 | 
					                "value": "x64",
 | 
				
			||||||
 | 
					                "strategy": "external"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "cacheVariables": {
 | 
				
			||||||
 | 
					                "CMAKE_BUILD_TYPE": "Debug"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "x64-release",
 | 
				
			||||||
 | 
					            "displayName": "x64 Release",
 | 
				
			||||||
 | 
					            "inherits": "x64-debug",
 | 
				
			||||||
 | 
					            "cacheVariables": {
 | 
				
			||||||
 | 
					                "CMAKE_BUILD_TYPE": "Release"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "x86-debug",
 | 
				
			||||||
 | 
					            "displayName": "x86 Debug",
 | 
				
			||||||
 | 
					            "inherits": "windows-base",
 | 
				
			||||||
 | 
					            "architecture": {
 | 
				
			||||||
 | 
					                "value": "x86",
 | 
				
			||||||
 | 
					                "strategy": "external"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "cacheVariables": {
 | 
				
			||||||
 | 
					                "CMAKE_BUILD_TYPE": "Debug"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "x86-release",
 | 
				
			||||||
 | 
					            "displayName": "x86 Release",
 | 
				
			||||||
 | 
					            "inherits": "x86-debug",
 | 
				
			||||||
 | 
					            "cacheVariables": {
 | 
				
			||||||
 | 
					                "CMAKE_BUILD_TYPE": "Release"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "linux-debug",
 | 
				
			||||||
 | 
					            "displayName": "Linux Debug",
 | 
				
			||||||
 | 
					            "generator": "Ninja",
 | 
				
			||||||
 | 
					            "binaryDir": "${sourceDir}/out/build/${presetName}",
 | 
				
			||||||
 | 
					            "installDir": "${sourceDir}/out/install/${presetName}",
 | 
				
			||||||
 | 
					            "cacheVariables": {
 | 
				
			||||||
 | 
					                "CMAKE_BUILD_TYPE": "Debug"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "condition": {
 | 
				
			||||||
 | 
					                "type": "equals",
 | 
				
			||||||
 | 
					                "lhs": "${hostSystemName}",
 | 
				
			||||||
 | 
					                "rhs": "Linux"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "vendor": {
 | 
				
			||||||
 | 
					                "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
 | 
				
			||||||
 | 
					                    "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "macos-debug",
 | 
				
			||||||
 | 
					            "displayName": "macOS Debug",
 | 
				
			||||||
 | 
					            "generator": "Ninja",
 | 
				
			||||||
 | 
					            "binaryDir": "${sourceDir}/out/build/${presetName}",
 | 
				
			||||||
 | 
					            "installDir": "${sourceDir}/out/install/${presetName}",
 | 
				
			||||||
 | 
					            "cacheVariables": {
 | 
				
			||||||
 | 
					                "CMAKE_BUILD_TYPE": "Debug"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "condition": {
 | 
				
			||||||
 | 
					                "type": "equals",
 | 
				
			||||||
 | 
					                "lhs": "${hostSystemName}",
 | 
				
			||||||
 | 
					                "rhs": "Darwin"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "vendor": {
 | 
				
			||||||
 | 
					                "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
 | 
				
			||||||
 | 
					                    "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					# CMakeList.txt: tinyrender 的 CMake 项目,在此处包括源代码并定义
 | 
				
			||||||
 | 
					# 项目特定的逻辑。
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 将源代码添加到此项目的可执行文件。
 | 
				
			||||||
 | 
					add_executable (tinyrender "main.cpp" "tgaimage.h" "tgaimage.cpp")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (CMAKE_VERSION VERSION_GREATER 3.12)
 | 
				
			||||||
 | 
					  set_property(TARGET tinyrender PROPERTY CXX_STANDARD 20)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TODO: 如有需要,请添加测试并安装目标。
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,355 @@
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
 | 
					#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; i < chunkheader; i++) {
 | 
				
			||||||
 | 
									in.read((char*)colorbuffer.raw, bytespp);
 | 
				
			||||||
 | 
									if (!in.good()) {
 | 
				
			||||||
 | 
										std::cerr << "an error occured while reading the header\n";
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									for (int t = 0; t < bytespp; t++)
 | 
				
			||||||
 | 
										data[currentbyte++] = colorbuffer.raw[t];
 | 
				
			||||||
 | 
									currentpixel++;
 | 
				
			||||||
 | 
									if (currentpixel > pixelcount) {
 | 
				
			||||||
 | 
										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; i < chunkheader; i++) {
 | 
				
			||||||
 | 
									for (int t = 0; t < bytespp; t++)
 | 
				
			||||||
 | 
										data[currentbyte++] = colorbuffer.raw[t];
 | 
				
			||||||
 | 
									currentpixel++;
 | 
				
			||||||
 | 
									if (currentpixel > pixelcount) {
 | 
				
			||||||
 | 
										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 < npixels) {
 | 
				
			||||||
 | 
							unsigned long chunkstart = curpix * bytespp;
 | 
				
			||||||
 | 
							unsigned long curbyte = curpix * bytespp;
 | 
				
			||||||
 | 
							unsigned char run_length = 1;
 | 
				
			||||||
 | 
							bool raw = true;
 | 
				
			||||||
 | 
							while (curpix + run_length < npixels && run_length < max_chunk_length) {
 | 
				
			||||||
 | 
								bool succ_eq = true;
 | 
				
			||||||
 | 
								for (int t = 0; succ_eq && t < bytespp; t++) {
 | 
				
			||||||
 | 
									succ_eq = (data[curbyte + t] == data[curbyte + t + bytespp]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								curbyte += bytespp;
 | 
				
			||||||
 | 
								if (1 == run_length) {
 | 
				
			||||||
 | 
									raw = !succ_eq;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (raw && succ_eq) {
 | 
				
			||||||
 | 
									run_length--;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (!raw && !succ_eq) {
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								run_length++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							curpix += run_length;
 | 
				
			||||||
 | 
							out.put(raw ? run_length - 1 : run_length + 127);
 | 
				
			||||||
 | 
							if (!out.good()) {
 | 
				
			||||||
 | 
								std::cerr << "can't dump the tga file\n";
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							out.write((char*)(data + chunkstart), (raw ? run_length * bytespp : bytespp));
 | 
				
			||||||
 | 
							if (!out.good()) {
 | 
				
			||||||
 | 
								std::cerr << "can't dump the tga file\n";
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TGAColor TGAImage::get(int x, int y) {
 | 
				
			||||||
 | 
						if (!data || x < 0 || y < 0 || x >= 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 < half; i++) {
 | 
				
			||||||
 | 
							for (int j = 0; j < height; j++) {
 | 
				
			||||||
 | 
								TGAColor c1 = get(i, j);
 | 
				
			||||||
 | 
								TGAColor c2 = get(width - 1 - i, j);
 | 
				
			||||||
 | 
								set(i, j, c2);
 | 
				
			||||||
 | 
								set(width - 1 - i, j, c1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool TGAImage::flip_vertically() {
 | 
				
			||||||
 | 
						if (!data) return false;
 | 
				
			||||||
 | 
						unsigned long bytes_per_line = width * bytespp;
 | 
				
			||||||
 | 
						unsigned char* line = new unsigned char[bytes_per_line];
 | 
				
			||||||
 | 
						int half = height >> 1;
 | 
				
			||||||
 | 
						for (int j = 0; j < half; j++) {
 | 
				
			||||||
 | 
							unsigned long l1 = j * bytes_per_line;
 | 
				
			||||||
 | 
							unsigned long l2 = (height - 1 - j) * bytes_per_line;
 | 
				
			||||||
 | 
							memmove((void*)line, (void*)(data + l1), bytes_per_line);
 | 
				
			||||||
 | 
							memmove((void*)(data + l1), (void*)(data + l2), bytes_per_line);
 | 
				
			||||||
 | 
							memmove((void*)(data + l2), (void*)line, bytes_per_line);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						delete[] line;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned char* TGAImage::buffer() {
 | 
				
			||||||
 | 
						return data;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void TGAImage::clear() {
 | 
				
			||||||
 | 
						memset((void*)data, 0, width * height * bytespp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool TGAImage::scale(int w, int h) {
 | 
				
			||||||
 | 
						if (w <= 0 || h <= 0 || !data) return false;
 | 
				
			||||||
 | 
						unsigned char* tdata = new unsigned char[w * h * bytespp];
 | 
				
			||||||
 | 
						int nscanline = 0;
 | 
				
			||||||
 | 
						int oscanline = 0;
 | 
				
			||||||
 | 
						int erry = 0;
 | 
				
			||||||
 | 
						unsigned long nlinebytes = w * bytespp;
 | 
				
			||||||
 | 
						unsigned long olinebytes = width * bytespp;
 | 
				
			||||||
 | 
						for (int j = 0; j < height; j++) {
 | 
				
			||||||
 | 
							int errx = width - w;
 | 
				
			||||||
 | 
							int nx = -bytespp;
 | 
				
			||||||
 | 
							int ox = -bytespp;
 | 
				
			||||||
 | 
							for (int i = 0; i < width; i++) {
 | 
				
			||||||
 | 
								ox += bytespp;
 | 
				
			||||||
 | 
								errx += w;
 | 
				
			||||||
 | 
								while (errx >= (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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,96 @@
 | 
				
			||||||
 | 
					#ifndef __IMAGE_H__
 | 
				
			||||||
 | 
					#define __IMAGE_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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 < bpp; i++) {
 | 
				
			||||||
 | 
								raw[i] = p[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TGAColor& operator =(const TGAColor& c) {
 | 
				
			||||||
 | 
							if (this != &c) {
 | 
				
			||||||
 | 
								bytespp = c.bytespp;
 | 
				
			||||||
 | 
								val = c.val;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return *this;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TGAImage {
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						unsigned char* data;
 | 
				
			||||||
 | 
						int width;
 | 
				
			||||||
 | 
						int height;
 | 
				
			||||||
 | 
						int bytespp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool   load_rle_data(std::ifstream& in);
 | 
				
			||||||
 | 
						bool unload_rle_data(std::ofstream& out);
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						enum Format {
 | 
				
			||||||
 | 
							GRAYSCALE = 1, RGB = 3, RGBA = 4
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TGAImage();
 | 
				
			||||||
 | 
						TGAImage(int w, int h, int bpp);
 | 
				
			||||||
 | 
						TGAImage(const TGAImage& img);
 | 
				
			||||||
 | 
						bool read_tga_file(const char* filename);
 | 
				
			||||||
 | 
						bool write_tga_file(const char* filename, bool rle = true);
 | 
				
			||||||
 | 
						bool flip_horizontally();
 | 
				
			||||||
 | 
						bool flip_vertically();
 | 
				
			||||||
 | 
						bool scale(int w, int h);
 | 
				
			||||||
 | 
						TGAColor get(int x, int y);
 | 
				
			||||||
 | 
						bool set(int x, int y, TGAColor c);
 | 
				
			||||||
 | 
						~TGAImage();
 | 
				
			||||||
 | 
						TGAImage& operator =(const TGAImage& img);
 | 
				
			||||||
 | 
						int get_width();
 | 
				
			||||||
 | 
						int get_height();
 | 
				
			||||||
 | 
						int get_bytespp();
 | 
				
			||||||
 | 
						unsigned char* buffer();
 | 
				
			||||||
 | 
						void clear();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //__IMAGE_H__
 | 
				
			||||||
		Loading…
	
		Reference in New Issue