diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f1229f --- /dev/null +++ b/.gitignore @@ -0,0 +1,350 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ \ No newline at end of file diff --git a/OpenWindow.sln b/OpenWindow.sln new file mode 100644 index 0000000..35fcdee --- /dev/null +++ b/OpenWindow.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.852 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenWindow", "OpenWindow\OpenWindow.vcxproj", "{42971E68-F861-4D45-9DA6-F5E163705584}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {42971E68-F861-4D45-9DA6-F5E163705584}.Debug|x64.ActiveCfg = Debug|x64 + {42971E68-F861-4D45-9DA6-F5E163705584}.Debug|x64.Build.0 = Debug|x64 + {42971E68-F861-4D45-9DA6-F5E163705584}.Debug|x86.ActiveCfg = Debug|Win32 + {42971E68-F861-4D45-9DA6-F5E163705584}.Debug|x86.Build.0 = Debug|Win32 + {42971E68-F861-4D45-9DA6-F5E163705584}.Release|x64.ActiveCfg = Release|x64 + {42971E68-F861-4D45-9DA6-F5E163705584}.Release|x64.Build.0 = Release|x64 + {42971E68-F861-4D45-9DA6-F5E163705584}.Release|x86.ActiveCfg = Release|Win32 + {42971E68-F861-4D45-9DA6-F5E163705584}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E8F2DE00-C3E8-4801-B6A2-84B81D8359A9} + EndGlobalSection +EndGlobal diff --git a/OpenWindow/OpenWindow.vcxproj b/OpenWindow/OpenWindow.vcxproj new file mode 100644 index 0000000..6ec45ac --- /dev/null +++ b/OpenWindow/OpenWindow.vcxproj @@ -0,0 +1,135 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {42971E68-F861-4D45-9DA6-F5E163705584} + OpenWindow + 10.0.18362.0 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + true + + + + + Level3 + Disabled + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenWindow/OpenWindow.vcxproj.filters b/OpenWindow/OpenWindow.vcxproj.filters new file mode 100644 index 0000000..53f3b63 --- /dev/null +++ b/OpenWindow/OpenWindow.vcxproj.filters @@ -0,0 +1,54 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/OpenWindow/african_head_diffuse.tga b/OpenWindow/african_head_diffuse.tga new file mode 100644 index 0000000..bdd085f Binary files /dev/null and b/OpenWindow/african_head_diffuse.tga differ diff --git a/OpenWindow/african_head_nm_tangent.tga b/OpenWindow/african_head_nm_tangent.tga new file mode 100644 index 0000000..46ee251 Binary files /dev/null and b/OpenWindow/african_head_nm_tangent.tga differ diff --git a/OpenWindow/geometry.cpp b/OpenWindow/geometry.cpp new file mode 100644 index 0000000..3b6b2f2 --- /dev/null +++ b/OpenWindow/geometry.cpp @@ -0,0 +1,7 @@ +#include "geometry.h" + +template <> template <> vec<3,int> ::vec(const vec<3,float> &v) : x(int(v.x+.5f)),y(int(v.y+.5f)),z(int(v.z+.5f)) {} +template <> template <> vec<3,float>::vec(const vec<3,int> &v) : x(v.x),y(v.y),z(v.z) {} +template <> template <> vec<2,int> ::vec(const vec<2,float> &v) : x(int(v.x+.5f)),y(int(v.y+.5f)) {} +template <> template <> vec<2,float>::vec(const vec<2,int> &v) : x(v.x),y(v.y) {} + diff --git a/OpenWindow/geometry.h b/OpenWindow/geometry.h new file mode 100644 index 0000000..630234a --- /dev/null +++ b/OpenWindow/geometry.h @@ -0,0 +1,237 @@ +#ifndef __GEOMETRY_H__ +#define __GEOMETRY_H__ +#include +#include +#include +#include + +template class mat; + +template struct vec { + vec() { for (size_t i=DIM; i--; data_[i] = T()); } + T& operator[](const size_t i) { assert(i struct vec<2,T> { + vec() : x(T()), y(T()) {} + vec(T X, T Y) : x(X), y(Y) {} + template vec<2,T>(const vec<2,U> &v); + T& operator[](const size_t i) { assert(i<2); return i<=0 ? x : y; } + const T& operator[](const size_t i) const { assert(i<2); return i<=0 ? x : y; } + + T x,y; +}; + +///////////////////////////////////////////////////////////////////////////////// + +template struct vec<3,T> { + vec() : x(T()), y(T()), z(T()) {} + vec(T X, T Y, T Z) : x(X), y(Y), z(Z) {} + vec(vec<4, T> v) : x(v.x/v.w), y(v.y/v.w), z(v.z/v.w) {} + template vec<3,T>(const vec<3,U> &v); + T& operator[](const size_t i) { assert(i<3); return i<=0 ? x : (1==i ? y : z); } + const T& operator[](const size_t i) const { assert(i<3); return i<=0 ? x : (1==i ? y : z); } + float norm() { return std::sqrt(x*x+y*y+z*z); } + vec<3,T> & normalize(T l=1) { *this = (*this)*(l/norm()); return *this; } + + T x,y,z; +}; + +///////////////////////////////////////////////////////////////////////////////// + +template struct vec<4,T> { + vec() : x(T()), y(T()), z(T()), w(T()) {} + vec(T X, T Y, T Z, T W) : x(X), y(Y), z(Z), w(W) {} + vec(vec<3, T> v) : x(v.x), y(v.y), z(v.z), w(1) {} + template vec<4,T>(const vec<4,U> &v); + T& operator[](const size_t i) { assert(i<4); return i<=0 ? x : (1==i ? y : (2==i ? z : w)); } + const T& operator[](const size_t i) const { assert(i<4); return i<=0 ? x : (1==i ? y : (2==i ? z : w)); } + float norm() { return std::sqrt(x*x+y*y+z*z+w*w); } + vec<4,T> & normalize(T l=1) { *this = (*this)*(l/norm()); return *this; } + + T x,y,z,w; +}; + +///////////////////////////////////////////////////////////////////////////////// + +template T operator*(const vec& lhs, const vec& rhs) { + T ret = T(); + for (size_t i=DIM; i--; ret+=lhs[i]*rhs[i]); + return ret; +} + + +templatevec operator+(vec lhs, const vec& rhs) { + for (size_t i=DIM; i--; lhs[i]+=rhs[i]); + return lhs; +} + +templatevec operator-(vec lhs, const vec& rhs) { + for (size_t i=DIM; i--; lhs[i]-=rhs[i]); + return lhs; +} + +template vec operator*(vec lhs, const U& rhs) { + for (size_t i=DIM; i--; lhs[i]*=rhs); + return lhs; +} + +template vec operator/(vec lhs, const U& rhs) { + for (size_t i=DIM; i--; lhs[i]/=rhs); + return lhs; +} + +template vec embed(const vec &v, T fill=1) { + vec ret; + for (size_t i=LEN; i--; ret[i]=(i vec proj(const vec &v) { + vec ret; + for (size_t i=LEN; i--; ret[i]=v[i]); + return ret; +} + +template vec<3,T> cross(vec<3,T> v1, vec<3,T> v2) { + return vec<3,T>(v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x); +} + +template std::ostream& operator<<(std::ostream& out, vec& v) { + for(unsigned int i=0; i struct dt { + static T det(const mat& src) { + T ret=0; + for (size_t i=DIM; i--; ret += src[0][i]*src.cofactor(0,i)); + return ret; + } +}; + +template struct dt<1,T> { + static T det(const mat<1,1,T>& src) { + return src[0][0]; + } +}; + +///////////////////////////////////////////////////////////////////////////////// + +template class mat { + vec rows[DimRows]; +public: + mat() {} + + vec& operator[] (const size_t idx) { + assert(idx& operator[] (const size_t idx) const { + assert(idx col(const size_t idx) const { + assert(idx ret; + for (size_t i=DimRows; i--; ret[i]=rows[i][idx]); + return ret; + } + + void set_col(size_t idx, vec v) { + assert(idx identity() { + mat ret; + for (size_t i=DimRows; i--; ) + for (size_t j=DimCols;j--; ret[i][j]=(i==j)); + return ret; + } + + T det() const { + return dt::det(*this); + } + + mat get_minor(size_t row, size_t col) const { + mat ret; + for (size_t i=DimRows-1; i--; ) + for (size_t j=DimCols-1;j--; ret[i][j]=rows[i adjugate() const { + mat ret; + for (size_t i=DimRows; i--; ) + for (size_t j=DimCols; j--; ret[i][j]=cofactor(i,j)); + return ret; + } + + mat invert_transpose() { + mat ret = adjugate(); + T tmp = ret[0]*rows[0]; + return ret/tmp; + } + + mat invert() { + return invert_transpose().transpose(); + } + + mat transpose() { + mat ret; + for (size_t i=DimCols; i--; ret[i]=this->col(i)); + return ret; + } +}; + +///////////////////////////////////////////////////////////////////////////////// + +template vec operator*(const mat& lhs, const vec& rhs) { + vec ret; + for (size_t i=DimRows; i--; ret[i]=lhs[i]*rhs); + return ret; +} + +templatemat operator*(const mat& lhs, const mat& rhs) { + mat result; + for (size_t i=R1; i--; ) + for (size_t j=C2; j--; result[i][j]=lhs[i]*rhs.col(j)); + return result; +} + +templatemat operator/(mat lhs, const T& rhs) { + for (size_t i=DimRows; i--; lhs[i]=lhs[i]/rhs); + return lhs; +} + +template std::ostream& operator<<(std::ostream& out, mat& m) { + for (size_t i=0; i Vec2f; +typedef vec<2, int> Vec2i; +typedef vec<3, float> Vec3f; +typedef vec<3, int> Vec3i; +typedef vec<4, float> Vec4f; +typedef mat<4,4,float> Matrix; +#endif //__GEOMETRY_H__ + diff --git a/OpenWindow/main.cpp b/OpenWindow/main.cpp new file mode 100644 index 0000000..85583cc --- /dev/null +++ b/OpenWindow/main.cpp @@ -0,0 +1,53 @@ +//#include +#include "util_window.h" +#include "renderer.h" +#include "ctime" + +const int width = 800; +const int height = 800; + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + HWND hwnd; + MSG Msg; + + hwnd = create_window(width, height, hInstance); + ShowWindow(hwnd, nCmdShow); + + char debug_str[100]; + + clock_t first_time = clock(); + render(); + clock_t end_time = clock(); + Update(); + + sprintf_s(debug_str, "%f\n", (double)(end_time - first_time) / CLOCKS_PER_SEC); + OutputDebugString(debug_str); + + while (GetMessage(&Msg, NULL, 0, 0)) + { + TranslateMessage(&Msg); + DispatchMessage(&Msg); + } + return Msg.wParam; +} + +LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_RBUTTONDOWN: + break; + case WM_LBUTTONDOWN: + Update(); + break; + case WM_CLOSE: + DestroyWindow(hwnd); + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } +} diff --git a/OpenWindow/model.cpp b/OpenWindow/model.cpp new file mode 100644 index 0000000..2a327b5 --- /dev/null +++ b/OpenWindow/model.cpp @@ -0,0 +1,143 @@ +#include +#include +#include +#include "model.h" + +#define PI 3.14159265358979323846 +#define DEG2RAD PI/180 + +Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_(), diffusemap_(), normalmap_(), specularmap_() { + std::ifstream in; + Transform = Matrix::identity(); + Rotation = Matrix::identity(); + Scale = Matrix::identity(); + Translation = Matrix::identity(); + in.open (filename, std::ifstream::in); + if (in.fail()) return; + std::string line; + while (!in.eof()) { + std::getline(in, line); + std::istringstream iss(line.c_str()); + char trash; + if (!line.compare(0, 2, "v ")) { + iss >> trash; + Vec3f v; + for (int i=0;i<3;i++) iss >> v[i]; + verts_.push_back(v); + } else if (!line.compare(0, 3, "vn ")) { + iss >> trash >> trash; + Vec3f n; + for (int i=0;i<3;i++) iss >> n[i]; + norms_.push_back(n); + } else if (!line.compare(0, 3, "vt ")) { + iss >> trash >> trash; + Vec2f uv; + for (int i=0;i<2;i++) iss >> uv[i]; + uv_.push_back(uv); + } else if (!line.compare(0, 2, "f ")) { + std::vector f; + Vec3i tmp; + iss >> trash; + while (iss >> tmp[0] >> trash >> tmp[1] >> trash >> tmp[2]) { + for (int i=0; i<3; i++) tmp[i]--; // in wavefront obj all indices start at 1, not zero + f.push_back(tmp); + } + faces_.push_back(f); + } + } + std::cerr << "# v# " << verts_.size() << " f# " << faces_.size() << " vt# " << uv_.size() << " vn# " << norms_.size() << std::endl; + load_texture(filename, "_diffuse.tga", diffusemap_); + load_texture(filename, "_nm_tangent.tga", normalmap_); + //load_texture(filename, "_spec.tga", specularmap_); +} + +Model::~Model() {} + +void Model::ApplyTransform() { + Transform = Translation * Scale * Rotation; +} + +void Model::translate(Vec3f tr) { + Translation[0][3] += tr.x; + Translation[1][3] += tr.y; + Translation[2][3] += tr.z; +} +void Model::rotate(Vec3f rot) { + rot = rot * DEG2RAD; + + Rotation[0][0] = cosf(rot.y) * cosf(rot.z); + Rotation[0][1] = -cosf(rot.y) * sinf(rot.z); + Rotation[0][2] = sinf(rot.y); + Rotation[1][0] = sinf(rot.x)*sinf(rot.y)*cosf(rot.z) + cosf(rot.x) * sinf(rot.z); + Rotation[1][1] = -sinf(rot.x)*sinf(rot.y)*sinf(rot.z) + cosf(rot.x) * cosf(rot.z); + Rotation[1][2] = -sinf(rot.x)*cosf(rot.y); + Rotation[2][0] = -cosf(rot.x)*sinf(rot.y)*cosf(rot.z) + sinf(rot.x) * sinf(rot.z); + Rotation[2][1] = cosf(rot.x)*sinf(rot.y)*sinf(rot.z) + sinf(rot.x) * cosf(rot.z); + Rotation[2][2] = cosf(rot.x)*cosf(rot.y); +} +void Model::scale(Vec3f scl) { + Scale[0][0] = scl.x; + Scale[1][1] = scl.y; + Scale[2][2] = scl.z; +} + +int Model::nverts() { + return (int)verts_.size(); +} + +int Model::nfaces() { + return (int)faces_.size(); +} + +std::vector Model::face(int idx) { + std::vector face; + for (int i=0; i<(int)faces_[idx].size(); i++) face.push_back(faces_[idx][i][0]); + return face; +} + +Vec3f Model::vert(int i) { + return verts_[i]; +} + +Vec3f Model::vert(int iface, int nthvert) { + return verts_[faces_[iface][nthvert][0]]; +} + +void Model::load_texture(std::string filename, const char *suffix, TGAImage &img) { + std::string texfile(filename); + size_t dot = texfile.find_last_of("."); + if (dot!=std::string::npos) { + texfile = texfile.substr(0,dot) + std::string(suffix); + std::cerr << "texture file " << texfile << " loading " << (img.read_tga_file(texfile.c_str()) ? "ok" : "failed") << std::endl; + img.flip_vertically(); + } +} + +TGAColor Model::diffuse(Vec2f uvf) { + Vec2i uv(uvf[0]*diffusemap_.get_width(), uvf[1]*diffusemap_.get_height()); + return diffusemap_.get(uv[0], uv[1]); +} + +Vec3f Model::normal(Vec2f uvf) { + Vec2i uv(uvf[0]*normalmap_.get_width(), uvf[1]*normalmap_.get_height()); + TGAColor c = normalmap_.get(uv[0], uv[1]); + Vec3f res; + for (int i=0; i<3; i++) + res[2-i] = (float)c[i]/255.f*2.f - 1.f; + return res; +} + +Vec2f Model::uv(int iface, int nthvert) { + return uv_[faces_[iface][nthvert][1]]; +} + +float Model::specular(Vec2f uvf) { + Vec2i uv(uvf[0]*specularmap_.get_width(), uvf[1]*specularmap_.get_height()); + return specularmap_.get(uv[0], uv[1])[0]/1.f; +} + +Vec3f Model::normal(int iface, int nthvert) { + int idx = faces_[iface][nthvert][2]; + return norms_[idx].normalize(); +} + diff --git a/OpenWindow/model.h b/OpenWindow/model.h new file mode 100644 index 0000000..93951ef --- /dev/null +++ b/OpenWindow/model.h @@ -0,0 +1,41 @@ +#ifndef __MODEL_H__ +#define __MODEL_H__ +#include +#include +#include "geometry.h" +#include "tgaimage.h" + +class Model { +private: + std::vector verts_; + std::vector > faces_; // attention, this Vec3i means vertex/uv/normal + std::vector norms_; + std::vector uv_; + TGAImage diffusemap_; + TGAImage normalmap_; + TGAImage specularmap_; + void load_texture(std::string filename, const char *suffix, TGAImage &img); +public: + Model(const char *filename); + ~Model(); + int nverts(); + int nfaces(); + Vec3f normal(int iface, int nthvert); + Vec3f normal(Vec2f uv); + Vec3f vert(int i); + Vec3f vert(int iface, int nthvert); + Vec2f uv(int iface, int nthvert); + Matrix Transform; + Matrix Rotation; + Matrix Scale; + Matrix Translation; + void translate(Vec3f tr); + void rotate(Vec3f rot); + void scale(Vec3f scl); + void ApplyTransform(); + TGAColor diffuse(Vec2f uv); + float specular(Vec2f uv); + std::vector face(int idx); +}; +#endif //__MODEL_H__ + diff --git a/OpenWindow/output.tga b/OpenWindow/output.tga new file mode 100644 index 0000000..9eb084b Binary files /dev/null and b/OpenWindow/output.tga differ diff --git a/OpenWindow/renderer.cpp b/OpenWindow/renderer.cpp new file mode 100644 index 0000000..09f8a03 --- /dev/null +++ b/OpenWindow/renderer.cpp @@ -0,0 +1,232 @@ +#define _USE_MATH_DEFINES +#include +#include +#include +#include "tgaimage.h" +#include "model.h" +#include "geometry.h" +#include "renderer.h" +#include "util_window.h" +#include + +const TGAColor white = TGAColor(255, 255, 255, 255); +const TGAColor red = TGAColor(255, 0, 0, 255); +const TGAColor green = TGAColor(0, 255, 0, 255); +const TGAColor blue = TGAColor(0, 0, 255, 255); + +const int depth = 255; + +float* z_buffer; +Vec3f light_dir = Vec3f(0, 0, 1).normalize(); +Vec3f eye(0, 0, 3); +Vec3f center(0, 0, 0); + +Matrix viewport(int x, int y, int w, int h) { + Matrix m = Matrix::identity(); + m[0][3] = x + w / 2.f; + m[1][3] = y + h / 2.f; + m[2][3] = depth / 2.f; + + m[0][0] = w / 2.f; + m[1][1] = h / 2.f; + m[2][2] = depth / 2.f; + return m; +} + +void line(Vec2i p0, Vec2i p1, TGAImage &image, TGAColor color) +{ + bool steep = false; + + if (std::abs(p0[0] - p1[0]) < std::abs(p0[1] - p1[1])) { + std::swap(p0[0], p0[1]); + std::swap(p1[0], p1[1]); + steep = true; + + } + + if (p0[0] > p1[0]) { + std::swap(p0[0], p1[0]); + std::swap(p0[1], p1[1]); + } + + int dx = p1[0] - p0[0]; + int dy = p1[1] - p0[1]; + int derror2 = std::abs(dy) * 2; + int error2 = 0; + int y = p0[1]; + int y_step = p1[1] > p0[1] ? 1 : -1; + int dx_2 = 2 * dx; + + for (int x = p0[0]; x <= p1[0]; x++) { + if (steep) { + image.set(y, x, color); + } + else { + image.set(x, y, color); + } + error2 += derror2; + if (error2 > dx) { + y += (y_step); + error2 -= dx_2; + } + } +} + +Vec3f barycentric(Vec3f* pts, Vec3f P) +{ + Vec3f u = cross( + Vec3f(pts[2][0] - pts[0][0], pts[1][0] - pts[0][0], pts[0][0] - P[0]), // AC_x, AB_x, distance_x + Vec3f(pts[2][1] - pts[0][1], pts[1][1] - pts[0][1], pts[0][1] - P[1]) // AC_y, AB_y, distance_y + ); + + if (std::abs(u[2]) < 1) return Vec3f(-1, 1, 1); + return Vec3f(1.f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z); +} + + +void triangle( + Vec3f* pts, // Needed + Model* model, // Should be removed + Vec2f* diff_pts, // Should be removed + float* intensities, + Vec3f camera_pos) // Not really sure yet +{ + + if (pts[0].y == pts[1].y && pts[0].y == pts[2].y) return; // i dont care about degenerate triangles + if (pts[0].y > pts[1].y) { + std::swap(pts[0], pts[1]); + std::swap(diff_pts[0], diff_pts[1]); + std::swap(intensities[0], intensities[1]); + } + if (pts[0].y > pts[2].y) { + std::swap(pts[0], pts[2]); + std::swap(diff_pts[0], diff_pts[2]); + std::swap(intensities[0], intensities[2]); + } + if (pts[1].y > pts[2].y) { + std::swap(pts[1], pts[2]); + std::swap(diff_pts[1], diff_pts[2]); + std::swap(intensities[1], intensities[2]); + } + Vec2i bounding_box_min(screen_width - 1, screen_height - 1); + Vec2i bounding_box_max(0, 0); + Vec2i clamp(screen_width - 1, screen_height - 1); + TGAColor color = white; + + for(int i = 0; i < 3; i++) { + for(int j =0; j < 2; j++) { + bounding_box_min[j] = std::fmax(0, std::fmin(bounding_box_min[j], (int)pts[i][j])); + bounding_box_max[j] = std::fmin(clamp[j], std::fmax(bounding_box_max[j], (int)pts[i][j])); + } + } + + Vec3f P; + for(P.x = bounding_box_min.x; P.x <= bounding_box_max.x; P.x++) { + for(P.y = bounding_box_min.y; P.y <= bounding_box_max.y; P.y++) { + Vec3f bc_coord = barycentric(pts, P); + if(bc_coord.x < 0 || bc_coord.y < 0 || bc_coord.z < 0) continue; + + + float intensity = + intensities[0] + + (intensities[1] - intensities[0]) * bc_coord[1] + + (intensities[2] - intensities[0]) * bc_coord[2]; + + + // Interpolating Z using the barycentric coordinates + P.z = 0; + for(int i = 0; i < 3; i++) P.z += pts[i][2] * bc_coord[i]; + + // Coloring according to the Z-Buffer + if (P.z > z_buffer[(int)(P.x + P.y * screen_width)]) + { + z_buffer[(int)(P.x + P.y * screen_width)] = P.z; + + // If diff_pts (Diffusemap Points) were passed, then find the + // color of the current pixel + if(diff_pts) { + Vec2f diff_pt = + diff_pts[0] + + (diff_pts[1] - diff_pts[0]) * bc_coord[1] + + (diff_pts[2] - diff_pts[0]) * bc_coord[2]; + + color = model->diffuse(diff_pt); + } + color = color * intensity; + set_pixel(P.x, P.y, color_to_int(color)); + } + } + } +} + +int color_to_int(TGAColor col) { + return (col[2] << 16) | (col[1] << 8) | col[0]; +} + +void init_zbuffer() +{ + z_buffer = new float[screen_width*screen_height]; + for (int i = 0; i < screen_width * screen_height; i++) + z_buffer[i] = INT_MIN; +} + +Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) { + Vec3f z = (eye - center).normalize(); + Vec3f x = cross(up, z).normalize(); + Vec3f y = cross(z, x).normalize(); + Matrix Minv = Matrix::identity(); + Matrix Tr = Matrix::identity(); + for (int i = 0; i < 3; i++) { + Minv[0][i] = x[i]; + Minv[1][i] = y[i]; + Minv[2][i] = z[i]; + Tr[i][3] = -center[i]; + } + return Minv * Tr; +} + +void render() +{ + Model* model = new Model("african_head.obj"); + + Matrix ViewPort = viewport(screen_width / 8, screen_height / 8, screen_width * 3 / 4, screen_height * 3 / 4); + Matrix Projection = Matrix::identity(); + Matrix ModelView = lookat(eye, center, Vec3f(0, 1, 0)); + + Projection[3][2] = -1.f / (eye - center).norm(); + + model->rotate(Vec3f(0, 0, 90)); + model->scale(Vec3f(0.5, 0.5, 0.5)); + model->translate(Vec3f(0.5, 0.5, -1)); + + model->ApplyTransform(); + + Matrix z = ViewPort * Projection * ModelView * model->Transform; + + init_zbuffer(); + for (int i = 0; i < model->nfaces(); i++) + { + std::vector face = model->face(i); + Vec3f screen_coords[3]; + Vec3f world_coords[3]; + Vec2f diffuse_coords[3]; + float intensities[3]; + + for (int j = 0; j < 3; j++) + { + Vec3f v = model->vert(face[j]); + Vec4f v4(v); + Vec3f coord(z * v4); + + screen_coords[j] = coord; + world_coords[j] = v; + diffuse_coords[j] = model->uv(i, j); + intensities[j] = model->normal(i, j) * light_dir; + } + + triangle(screen_coords, model, diffuse_coords, intensities, Vec3f(0, 0, 5)); + } + + delete model; +} + diff --git a/OpenWindow/renderer.h b/OpenWindow/renderer.h new file mode 100644 index 0000000..f92dacb --- /dev/null +++ b/OpenWindow/renderer.h @@ -0,0 +1,7 @@ +#ifndef RENDERER_HEADER +#define RENDERER_HEADER +#include "tgaimage.h" + +void render(); +int color_to_int(TGAColor col); +#endif \ No newline at end of file diff --git a/OpenWindow/tgaimage.cpp b/OpenWindow/tgaimage.cpp new file mode 100644 index 0000000..47e6ff8 --- /dev/null +++ b/OpenWindow/tgaimage.cpp @@ -0,0 +1,356 @@ +#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) : data(NULL), 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.bgra, 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.bgra, bytespp); + return true; +} + +bool TGAImage::set(int x, int y, const TGAColor &c) { + if (!data || x<0 || y<0 || x>=width || y>=height) { + return false; + } + memcpy(data+(x+y*width)*bytespp, c.bgra, 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/OpenWindow/tgaimage.h b/OpenWindow/tgaimage.h new file mode 100644 index 0000000..63a944b --- /dev/null +++ b/OpenWindow/tgaimage.h @@ -0,0 +1,98 @@ +#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 { + unsigned char bgra[4]; + unsigned char bytespp; + + TGAColor() : bgra(), bytespp(1) { + for (int i=0; i<4; i++) bgra[i] = 0; + } + + TGAColor(unsigned char R, unsigned char G, unsigned char B, unsigned char A=255) : bgra(), bytespp(4) { + bgra[0] = B; + bgra[1] = G; + bgra[2] = R; + bgra[3] = A; + } + + TGAColor(unsigned char v) : bgra(), bytespp(1) { + for (int i=0; i<4; i++) bgra[i] = 0; + bgra[0] = v; + } + + + TGAColor(const unsigned char *p, unsigned char bpp) : bgra(), bytespp(bpp) { + for (int i=0; i<(int)bpp; i++) { + bgra[i] = p[i]; + } + for (int i=bpp; i<4; i++) { + bgra[i] = 0; + } + } + + unsigned char& operator[](const int i) { return bgra[i]; } + + TGAColor operator *(float intensity) const { + TGAColor res = *this; + intensity = (intensity>1.f?1.f:(intensity<0.f?0.f:intensity)); + for (int i=0; i<4; i++) res.bgra[i] = bgra[i]*intensity; + return res; + } +}; + +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); + bool set(int x, int y, const 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__ + diff --git a/OpenWindow/util_window.cpp b/OpenWindow/util_window.cpp new file mode 100644 index 0000000..5821618 --- /dev/null +++ b/OpenWindow/util_window.cpp @@ -0,0 +1,112 @@ +#include "util_window.h" +#include + +const char* wnd_class_name = "Renderer To-Be"; +void* pixels; +char* pixel_data; +BITMAPINFO info; +HBITMAP hbm; +const int BITCOUNT_PER_PIXEL = 24; +const int title_height = 39; +int screen_width = 0; +int screen_height = 0; +long long bytes_per_row; +bool screen_changed = false; +HDC hdc; +HDRAWDIB hdd; +HDC bitmap_dc; +HGDIOBJ old_obj; + +HWND create_window(int width, int height, HINSTANCE &hInstance) { + HWND hWnd; + WNDCLASSEX wnd_class = { 0 }; + init_wnd_class(wnd_class, hInstance); + + RegisterClassEx(&wnd_class); + + screen_width = width; + screen_height = height; + create_hwnd(hWnd, hInstance); + init(hWnd); + + return hWnd; +} + +void init(HWND &hWnd) { + memset(&info, 0, sizeof(info)); + info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + info.bmiHeader.biWidth = screen_width; + info.bmiHeader.biHeight = screen_height; + info.bmiHeader.biPlanes = 1; + info.bmiHeader.biBitCount = BITCOUNT_PER_PIXEL; + info.bmiHeader.biCompression = BI_RGB; + + hdc = GetDC(hWnd); + pixels = NULL; + hbm = CreateDIBSection(hdc, &info, DIB_RGB_COLORS, &pixels, NULL, 0); + pixel_data = (char*)pixels; + + hdd = DrawDibOpen(); + + bitmap_dc = CreateCompatibleDC(hdc); + old_obj = SelectObject(bitmap_dc, hbm); + bytes_per_row = ceil(screen_width * 0.03) * 100; +} + +void create_hwnd(HWND &hwnd, HINSTANCE &hInstance) +{ + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + TEXT(wnd_class_name), + TEXT("Renderer To-be"), // window caption + WS_OVERLAPPEDWINDOW, // window style + 0, // initial x position + 0, // initial y position + screen_width + 16, // Some weird horizontal dead pixels + screen_height + title_height, + NULL, // parent window handle + NULL, // window menu handle + hInstance, // program instance handle + NULL); // creation parameters +} + +void init_wnd_class(WNDCLASSEX &wndClass, HINSTANCE &hInstance) { + wndClass.cbSize = sizeof(WNDCLASSEX); + wndClass.style = 0; + wndClass.lpfnWndProc = WndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = hInstance; + wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wndClass.lpszMenuName = NULL; + wndClass.lpszClassName = TEXT(wnd_class_name); + wndClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); +} + +void destroy_window() { + DrawDibEnd(hdd); + DrawDibClose(hdd); + SelectObject(bitmap_dc, old_obj); + DeleteDC(hdc); + DeleteDC(bitmap_dc); + DeleteObject(hbm); + DeleteObject(old_obj); +} + + +void set_pixel(unsigned int x, unsigned int y, unsigned int color) { + unsigned long pixel_index = y * bytes_per_row + x * 3; + + pixel_data[pixel_index + 0] = (char)(color >> 0); + pixel_data[pixel_index + 1] = (char)(color >> 8); + pixel_data[pixel_index + 2] = (char)(color >> 16); + + if (!screen_changed) + screen_changed = true; +} + +void Update() { + DrawDibDraw(hdd, hdc, 0, 0, screen_width, screen_height, &info.bmiHeader, pixels, 0, 0, screen_width, screen_height, 0); +} diff --git a/OpenWindow/util_window.h b/OpenWindow/util_window.h new file mode 100644 index 0000000..c9f5776 --- /dev/null +++ b/OpenWindow/util_window.h @@ -0,0 +1,35 @@ +#ifndef UTIL_HEADER +#define UTIL_HEADER + +#include +#include +#pragma comment(lib, "Vfw32.lib") + +extern const char* wnd_class_name; +extern void* pixels; +extern char* pixel_data; +extern BITMAPINFO info; +extern HBITMAP hbm; +extern const int BITCOUNT_PER_PIXEL; +extern const int title_height; +extern long long bytes_per_row; +extern bool screen_changed; +extern HDC hdc; +extern HDRAWDIB hdd; +extern HDC bitmap_dc; +extern HGDIOBJ old_obj; +extern int screen_width; +extern int screen_height; + + +void init(HWND &hWnd); +void destroy_window(); +HWND create_window(int width, int height, HINSTANCE &hInstance); +void create_hwnd(HWND &hwnd, HINSTANCE &hInstance); +void init_wnd_class(WNDCLASSEX &wndClass, HINSTANCE &hInstance); +void set_pixel(unsigned int x, unsigned int y, unsigned int color); +void Update(); + +LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +#endif