diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ef4915..5800646 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,8 +18,8 @@ set(MATH quaternion.cpp vector.cpp matrix.cpp rayCaster.cpp) set(RENDER lineRenderer.cpp particleEmitter.cpp camera.cpp light.cpp material.cpp mesh.cpp meshData.cpp model.cpp node.cpp quad.cpp box.cpp root.cpp shader.cpp texture.cpp) set(ANIM animationController.cpp animationChannel.cpp animation.cpp animatable.cpp keyframeChannel.cpp driver.cpp) set(ARMATURE skeleton.cpp bone.cpp ikSolver.cpp) -set(ASSET_MANAGER assetManager.cpp textAsset.h imageAsset.h modelAsset.h fontAsset.h) -set(ASSET_READERS imageReader.cpp fontReader.cpp modelReader.cpp xmlModelReader.cpp) +set(ASSET_MANAGER assetManager.cpp shaderAsset.h textAsset.h imageAsset.h modelAsset.h fontAsset.h) +set(ASSET_READERS shaderReader.cpp imageReader.cpp fontReader.cpp modelReader.cpp xmlModelReader.cpp) if(BUILD_WITH_ASSIMP) set(ASSET_READERS ${ASSET_READERS} assimpModelReader.cpp) diff --git a/abstractGuiManager.cpp b/abstractGuiManager.cpp index 5c37d69..df06b81 100644 --- a/abstractGuiManager.cpp +++ b/abstractGuiManager.cpp @@ -154,6 +154,14 @@ namespace vb01Gui{ textboxes.push_back(t); } + Button* AbstractGuiManager::getButton(string name){ + for(Button *b : buttons) + if(b->getName() == name) + return b; + + return nullptr; + } + void AbstractGuiManager::removeButton(Button *b) { for (int i = 0; i < buttons.size(); i++) { if (b == buttons[i]) { diff --git a/abstractGuiManager.h b/abstractGuiManager.h index 90de87f..6eac215 100644 --- a/abstractGuiManager.h +++ b/abstractGuiManager.h @@ -22,6 +22,7 @@ namespace vb01Gui{ std::vector findClickedButtons(); void updateGui(); void addButton(Button *b){buttons.push_back(b);} + Button* getButton(std::string); void removeButton(Button*); void removeButton(std::string); void addListbox(Listbox*); diff --git a/assetManager.cpp b/assetManager.cpp index 63b106b..8bdfdf8 100644 --- a/assetManager.cpp +++ b/assetManager.cpp @@ -1,8 +1,13 @@ #include "assetManager.h" #include "abstractAssetReader.h" #include "util.h" +#include "root.h" +#include "node.h" +#include "mesh.h" +#include "material.h" #include "imageReader.h" #include "fontReader.h" +#include "shaderReader.h" #include "xmlModelReader.h" #include @@ -71,6 +76,11 @@ namespace vb01{ if(find(modelFormats.begin(), modelFormats.end(), format) != modelFormats.end()) assetReader = XmlModelReader::getSingleton(); + vector shaderFormats = vector{"vert", "frag", "geo"}; + + if(find(shaderFormats.begin(), shaderFormats.end(), format) != shaderFormats.end()) + assetReader = ShaderReader::getSingleton(); + if(assetReader) assets.push_back(assetReader->readAsset(file)); else @@ -85,4 +95,28 @@ namespace vb01{ return nullptr; } + + void AssetManager::editAsset(string path, Asset &newAsset){ + ShaderAsset *oldAsset = (ShaderAsset*)getAsset(path); + + if(oldAsset){ + oldAsset->shaderString = ((ShaderAsset&)newAsset).shaderString; + + Root *root = Root::getSingleton(); + vector descendants; + root->getRootNode()->getDescendants(descendants); + root->getGuiNode()->getDescendants(descendants); + + for(Node *desc : descendants){ + vector meshes = desc->getMeshes(); + + for(Mesh *mesh : meshes){ + Material *mat = mesh->getMaterial(); + + if(mat) + mat->getShader()->loadShaders(); + } + } + } + } } diff --git a/assetManager.h b/assetManager.h index 262e9c1..d84e4f7 100644 --- a/assetManager.h +++ b/assetManager.h @@ -12,6 +12,7 @@ namespace vb01{ public: static AssetManager* getSingleton(); void load(std::string, bool = false); + void editAsset(std::string, Asset&); Asset* getAsset(std::string); inline Asset* getAsset(int i){return assets[i];} inline std::vector getAssets(){return assets;} diff --git a/box.cpp b/box.cpp index f69613a..671656b 100755 --- a/box.cpp +++ b/box.cpp @@ -9,27 +9,23 @@ namespace vb01{ void Box::setSize(Vector3 size){ this->size = size; - Vector3 pos[] = { - Vector3(size.x / 2, size.y / 2, size.z / 2), - Vector3(-size.x / 2, size.y / 2, size.z / 2), - Vector3(-size.x / 2, size.y / 2, -size.z / 2), - Vector3(size.x / 2, size.y / 2, -size.z / 2), + Vector3 *pos = new Vector3[8]; + pos[0] = Vector3(size.x / 2, size.y / 2, size.z / 2); + pos[1] = Vector3(-size.x / 2, size.y / 2, size.z / 2); + pos[2] = Vector3(-size.x / 2, size.y / 2, -size.z / 2); + pos[3] = Vector3(size.x / 2, size.y / 2, -size.z / 2); + pos[4] = Vector3(size.x / 2, -size.y / 2, size.z / 2); + pos[5] = Vector3(-size.x / 2, -size.y / 2, size.z / 2); + pos[6] = Vector3(-size.x / 2, -size.y / 2, -size.z / 2); + pos[7] = Vector3(size.x / 2, -size.y / 2, -size.z / 2); - Vector3(size.x / 2, -size.y / 2, size.z / 2), - Vector3(-size.x / 2, -size.y / 2, size.z / 2), - Vector3(-size.x / 2, -size.y / 2, -size.z / 2), - Vector3(size.x / 2, -size.y / 2, -size.z / 2) - }; - - Vector3 norm[] = { - Vector3(0, 0, 1), - Vector3(0, 1, 0), - Vector3(1, 0, 0), - - Vector3(0, 0, -1), - Vector3(0, -1, 0), - Vector3(-1, 0, 0) - }; + Vector3 *norm = new Vector3[6]; + norm[0] = Vector3(0, 0, 1); + norm[1] = Vector3(0, 1, 0); + norm[2] = Vector3(1, 0, 0); + norm[3] = Vector3(0, 0, -1); + norm[4] = Vector3(0, -1, 0); + norm[5] = Vector3(-1, 0, 0); Vector2 tex[] = { Vector2(1, 1), @@ -63,14 +59,14 @@ namespace vb01{ MeshData::Vertex *vertices = new MeshData::Vertex[3 * numTris]; for(int i = 0; i < 3 * numTris; i++){ - MeshData::Vertex v; - v.pos = pos[data[3 * i]]; - v.norm = norm[data[3 * i + 1]]; + MeshData::Vertex v; + v.pos = &pos[data[3 * i]]; + v.norm = &norm[data[3 * i + 1]]; v.uv = tex[data[3 * i + 2]]; vertices[i] = v; indices[i] = i; } - meshBase = MeshData(vertices, indices, numTris); + meshBase = MeshData(pos, nullptr, nullptr, nullptr, 8, norm, vertices, indices, numTris); } } diff --git a/button.cpp b/button.cpp index 5f67102..503c835 100644 --- a/button.cpp +++ b/button.cpp @@ -46,7 +46,7 @@ namespace vb01Gui{ rectNode->attachMesh(rect); guiNode->attachChild(rectNode); - if(separate){ + if(separate && fontPath != ""){ text = new Text(fontPath, stringToWstring(name)); float sc = .2; diff --git a/button.h b/button.h index dc340c9..d49fc9f 100644 --- a/button.h +++ b/button.h @@ -24,18 +24,19 @@ namespace vb01Gui{ virtual void onMouseOver(); virtual void onMouseOff(); virtual void onClick(){} - inline vb01::Vector3 getPos(){return pos;} void setPos(vb01::Vector3); - inline vb01::Vector2 getSize(){return size;} void setSize(vb01::Vector2); + void setColor(vb01::Vector4); + void setImage(std::string); + inline vb01::Node* getRectNode(){return rectNode;} + inline vb01::Vector3 getPos(){return pos;} + inline vb01::Vector2 getSize(){return size;} inline std::string getName(){return name;} inline void setActive(bool active){this->active = active;} inline bool isSeparate(){return separate;} inline bool isActive(){return active;} inline vb01::Vector4 getColor(){return color;} inline int getTrigger(){return trigger;} - void setColor(vb01::Vector4); - void setImage(std::string); protected: int trigger, initWindowSize[2]; bool separate, active = true, mouseOver = false; diff --git a/external/stb/stb_image_write.h b/external/stb/stb_image_write.h new file mode 100644 index 0000000..e4b32ed --- /dev/null +++ b/external/stb/stb_image_write.h @@ -0,0 +1,1724 @@ +/* stb_image_write - v1.16 - public domain - http://nothings.org/stb + writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + + Before #including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + + in the file that you want to have the implementation. + + Will probably not work correctly with strict-aliasing optimizations. + +ABOUT: + + This header file is a library for writing images to C stdio or a callback. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation; though providing a custom + zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. + This library is designed for source code compactness and simplicity, + not optimal image file size or run-time performance. + +BUILDING: + + You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. + You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace + malloc,realloc,free. + You can #define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function + for PNG compression (instead of the builtin one), it must have the following signature: + unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); + The returned data will be freed with STBIW_FREE() (free() by default), + so it must be heap allocated with STBIW_MALLOC() (malloc() by default), + +UNICODE: + + If compiling for Windows and you wish to use Unicode filenames, compile + with + #define STBIW_WINDOWS_UTF8 + and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert + Windows wchar_t filenames to utf8. + +USAGE: + + There are five functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); + int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + + void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically + + There are also five equivalent functions that use an arbitrary write function. You are + expected to open/close your file-equivalent before and after calling these: + + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + + where the callback is: + void stbi_write_func(void *context, void *data, int size); + + You can configure it with these global variables: + int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE + int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression + int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode + + + You can define STBI_WRITE_NO_STDIO to disable the file variant of these + functions, so the library will not use stdio.h at all. However, this will + also disable HDR writing, because it requires stdio for formatted output. + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP format expands Y to RGB in the file format and does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) + + PNG allows you to set the deflate compression level by setting the global + variable 'stbi_write_png_compression_level' (it defaults to 8). + + HDR expects linear float data. Since the format is always 32-bit rgb(e) + data, alpha (if provided) is discarded, and for monochrome data it is + replicated across all three channels. + + TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed + data, set the global variable 'stbi_write_tga_with_rle' to 0. + + JPEG does ignore alpha channels in input data; quality is between 1 and 100. + Higher quality looks better but results in a bigger image. + JPEG baseline (no JPEG progressive). + +CREDITS: + + + Sean Barrett - PNG/BMP/TGA + Baldur Karlsson - HDR + Jean-Sebastien Guay - TGA monochrome + Tim Kelsey - misc enhancements + Alan Hickman - TGA RLE + Emmanuel Julien - initial file IO callback implementation + Jon Olick - original jo_jpeg.cpp code + Daniel Gibson - integrate JPEG, allow external zlib + Aarni Koskela - allow choosing PNG filter + + bugfixes: + github:Chribba + Guillaume Chereau + github:jry2 + github:romigrou + Sergio Gonzalez + Jonas Karlsson + Filip Wasil + Thatcher Ulrich + github:poppolopoppo + Patrick Boettcher + github:xeekworx + Cap Petschulat + Simon Rodriguez + Ivan Tikhonov + github:ignotion + Adam Schackart + Andrew Kensler + +LICENSE + + See end of file for license information. + +*/ + +#ifndef INCLUDE_STB_IMAGE_WRITE_H +#define INCLUDE_STB_IMAGE_WRITE_H + +#include + +// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' +#ifndef STBIWDEF +#ifdef STB_IMAGE_WRITE_STATIC +#define STBIWDEF static +#else +#ifdef __cplusplus +#define STBIWDEF extern "C" +#else +#define STBIWDEF extern +#endif +#endif +#endif + +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +STBIWDEF int stbi_write_tga_with_rle; +STBIWDEF int stbi_write_png_compression_level; +STBIWDEF int stbi_write_force_png_filter; +#endif + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); + +#ifdef STBIW_WINDOWS_UTF8 +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif +#endif + +typedef void stbi_write_func(void *context, void *data, int size); + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + +STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); + +#endif//INCLUDE_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif + #ifndef _CRT_NONSTDC_NO_DEPRECATE + #define _CRT_NONSTDC_NO_DEPRECATE + #endif +#endif + +#ifndef STBI_WRITE_NO_STDIO +#include +#endif // STBI_WRITE_NO_STDIO + +#include +#include +#include +#include + +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) +// ok +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." +#endif + +#ifndef STBIW_MALLOC +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_FREE(p) free(p) +#endif + +#ifndef STBIW_REALLOC_SIZED +#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#endif + + +#ifndef STBIW_MEMMOVE +#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#endif + + +#ifndef STBIW_ASSERT +#include +#define STBIW_ASSERT(x) assert(x) +#endif + +#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) + +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_png_compression_level = 8; +static int stbi_write_tga_with_rle = 1; +static int stbi_write_force_png_filter = -1; +#else +int stbi_write_png_compression_level = 8; +int stbi_write_tga_with_rle = 1; +int stbi_write_force_png_filter = -1; +#endif + +static int stbi__flip_vertically_on_write = 0; + +STBIWDEF void stbi_flip_vertically_on_write(int flag) +{ + stbi__flip_vertically_on_write = flag; +} + +typedef struct +{ + stbi_write_func *func; + void *context; + unsigned char buffer[64]; + int buf_used; +} stbi__write_context; + +// initialize a callback-based context +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) +{ + s->func = c; + s->context = context; +} + +#ifndef STBI_WRITE_NO_STDIO + +static void stbi__stdio_write(void *context, void *data, int size) +{ + fwrite(data,1,size,(FILE*) context); +} + +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) +#ifdef __cplusplus +#define STBIW_EXTERN extern "C" +#else +#define STBIW_EXTERN extern +#endif +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); + +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbiw__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = stbiw__fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); + return f != NULL; +} + +static void stbi__end_write_file(stbi__write_context *s) +{ + fclose((FILE *)s->context); +} + +#endif // !STBI_WRITE_NO_STDIO + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context,&x,1); + break; } + case '2': { int x = va_arg(v,int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x>>8); + s->func(s->context,b,2); + break; } + case '4': { stbiw_uint32 x = va_arg(v,int); + unsigned char b[4]; + b[0]=STBIW_UCHAR(x); + b[1]=STBIW_UCHAR(x>>8); + b[2]=STBIW_UCHAR(x>>16); + b[3]=STBIW_UCHAR(x>>24); + s->func(s->context,b,4); + break; } + default: + STBIW_ASSERT(0); + return; + } + } +} + +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); +} + +static void stbiw__write_flush(stbi__write_context *s) +{ + if (s->buf_used) { + s->func(s->context, &s->buffer, s->buf_used); + s->buf_used = 0; + } +} + +static void stbiw__putc(stbi__write_context *s, unsigned char c) +{ + s->func(s->context, &c, 1); +} + +static void stbiw__write1(stbi__write_context *s, unsigned char a) +{ + if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) + stbiw__write_flush(s); + s->buffer[s->buf_used++] = a; +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) +{ + int n; + if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) + stbiw__write_flush(s); + n = s->buf_used; + s->buf_used = n+3; + s->buffer[n+0] = a; + s->buffer[n+1] = b; + s->buffer[n+2] = c; +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + stbiw__write1(s, d[comp - 1]); + + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case + case 1: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + stbiw__write1(s, d[0]); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + stbiw__write1(s, d[comp - 1]); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ + stbiw_uint32 zero = 0; + int i,j, j_end; + + if (y <= 0) + return; + + if (stbi__flip_vertically_on_write) + vdir *= -1; + + if (vdir < 0) { + j_end = -1; j = y-1; + } else { + j_end = y; j = 0; + } + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + stbiw__write_flush(s); + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) +{ + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) +{ + if (comp != 4) { + // write RGB bitmap + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header + } else { + // RGBA bitmaps need a v4 header + // use BI_BITFIELDS mode with 32bpp and alpha mask + // (straight BI_RGB with alpha mask doesn't work in most readers) + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, + "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", + 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header + 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header + } +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif //!STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) +{ + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp-1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i,j,k; + int jend, jdir; + + stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y-1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *) data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + stbiw__write1(s, header); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + stbiw__write1(s, header); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } + stbiw__write_flush(s); + } + return 1; +} + +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR writer +// by Baldur Karlsson + +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + +#ifndef STBI_WRITE_NO_STDIO + +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +{ + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); + + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } +} + +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +{ + unsigned char lengthbyte = STBIW_UCHAR(length+128); + STBIW_ASSERT(length+128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); +} + +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +{ + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); +} + +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +{ + unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; + unsigned char rgbe[4]; + float linear[3]; + int x; + + scanlineheader[2] = (width&0xff00)>>8; + scanlineheader[3] = (width&0x00ff); + + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x=0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c,r; + /* encode into scratch buffer */ + for (x=0; x < width; x++) { + switch(ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width*0] = rgbe[0]; + scratch[x + width*1] = rgbe[1]; + scratch[x + width*2] = rgbe[2]; + scratch[x + width*3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c=0; c < 4; c++) { + unsigned char *comp = &scratch[width*c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r+2 < width) { + if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) + break; + ++r; + } + if (r+2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r-x; + if (len > 128) len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r-x; + if (len > 127) len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } + } + } + } +} + +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) +{ + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + +#ifdef __STDC_LIB_EXT1__ + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#else + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#endif + s->func(s->context, buffer, len); + + for(i=0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); + STBIW_FREE(scratch); + return 1; + } +} + +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +} + +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif // STBI_WRITE_NO_STDIO + + +////////////////////////////////////////////////////////////////////////////// +// +// PNG writer +// + +#ifndef STBIW_ZLIB_COMPRESS +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() +#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] + +#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) +#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbiw__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbiw__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +// default huffman tables +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) +#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) + +#define stbiw__ZHASH 16384 + +#endif // STBIW_ZLIB_COMPRESS + +STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ +#ifdef STBIW_ZLIB_COMPRESS + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; + static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; + static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; + static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); + if (hash_table == NULL) + return NULL; + if (quality < 5) quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1,1); // BFINAL = 1 + stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) { best=d; bestloc=hlist[j]; } + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int) (data+i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbiw__zlib_huff(j+257); + if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); + if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0,1); + + for (i=0; i < stbiw__ZHASH; ++i) + (void) stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + + // store uncompressed instead if compression was worse + if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { + stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 + for (j = 0; j < data_len;) { + int blocklen = data_len - j; + if (blocklen > 32767) blocklen = 32767; + stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression + stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN + stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN + stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); + memcpy(out+stbiw__sbn(out), data+j, blocklen); + stbiw__sbn(out) += blocklen; + j += blocklen; + } + } + + { + // compute adler32 on input + unsigned int s1=1, s2=0; + int blocklen = (int) (data_len % 5552); + j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } + s1 %= 65521; s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *) stbiw__sbraw(out); +#endif // STBIW_ZLIB_COMPRESS +} + +static unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else + static unsigned int crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + int i; + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +#endif +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); + if (pb <= pc) return STBIW_UCHAR(b); + return STBIW_UCHAR(c); +} + +// @OPTIMIZE: provide an option that always forces left-predict or paeth predict +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) +{ + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } +} + +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int force_filter = stbi_write_force_png_filter; + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int j,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + if (force_filter >= 5) { + force_filter = -1; + } + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x*n; ++i) { + est += abs((signed char) line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } + } + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; + } + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) filter_type; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + + f = stbiw__fopen(filename, "wb"); + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + + +/* *************************************************************************** + * + * JPEG writer + * + * This is based on Jon Olick's jo_jpeg.cpp: + * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html + */ + +static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, + 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; + +static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while(bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if(c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; +} + +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; + + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 + + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; + + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; + + *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; +} + +static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val-1 : val; + bits[1] = 1; + while(tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if(end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for(i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i]==0 && i<=end0pos; ++i) { + } + nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + int nrmarker; + for (nrmarker=1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if(end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; +} + +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; + static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; + static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; + static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; + static const unsigned short YAC_HT[256][2] = { + {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const unsigned short UVAC_HT[256][2] = { + {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, + 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; + static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; + static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, + 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; + + int row, col, i, k, subsample; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; + + if(!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } + + quality = quality ? quality : 90; + subsample = quality <= 90 ? 1 : 0; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + for(i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i]*quality+50)/100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i]*quality+50)/100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } + + for(row = 0, k = 0; row < 8; ++row) { + for(col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + { + static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; + static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; + const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), + 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + s->func(s->context, (void*)head0, sizeof(head0)); + s->func(s->context, (void*)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void*)head1, sizeof(head1)); + s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); + s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); + s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void*)head2, sizeof(head2)); + } + + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + int DCY=0, DCU=0, DCV=0; + int bitBuf=0, bitCnt=0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; + int x, y, pos; + if(subsample) { + for(y = 0; y < height; y += 16) { + for(x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for(row = y, pos = 0; row < y+16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for(yy = 0, pos = 0; yy < 8; ++yy) { + for(xx = 0; xx < 8; ++xx, ++pos) { + int j = yy*32+xx*2; + subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; + subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; + } + } + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + } else { + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } + + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); + + return 1; +} + +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +} + + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.16 (2021-07-11) + make Deflate code emit uncompressed blocks when it would otherwise expand + support writing BMPs with alpha channel + 1.15 (2020-07-13) unknown + 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels + 1.13 + 1.12 + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs + 1.09 (2018-02-11) + fix typo in zlib quality API, improve STB_I_W_STATIC in C++ + 1.08 (2018-01-29) + add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter + 1.07 (2017-07-24) + doc fix + 1.06 (2017-07-23) + writing JPEG (using Jon Olick's code) + 1.05 ??? + 1.04 (2017-03-03) + monochrome BMP expansion + 1.03 ??? + 1.02 (2016-04-02) + avoid allocating large structures on the stack + 1.01 (2016-01-16) + STBIW_REALLOC_SIZED: support allocators with no realloc support + avoid race-condition in crc initialization + minor compile issues + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/imageAsset.h b/imageAsset.h index 54a4a8c..1701c21 100644 --- a/imageAsset.h +++ b/imageAsset.h @@ -5,15 +5,16 @@ namespace vb01{ struct ImageAsset : public Asset{ - ImageAsset(std::string path, u8 *image, int width, int height){ + ImageAsset(std::string path, u8 *image, int width, int height, int numChannels){ this->path = path; this->image = image; this->width = width; this->height = height; + this->numChannels = numChannels; } u8 *image; - int width, height; + int width, height, numChannels; }; } diff --git a/imageReader.cpp b/imageReader.cpp index 5a95612..c32d787 100644 --- a/imageReader.cpp +++ b/imageReader.cpp @@ -18,6 +18,6 @@ namespace vb01{ stbi_set_flip_vertically_on_load(flip); int width, height, numChannels; u8 *data = stbi_load(path.c_str(), &width, &height, &numChannels, 0); - return new ImageAsset(path, data, width, height); + return new ImageAsset(path, data, width, height, numChannels); } } diff --git a/light.cpp b/light.cpp index 4984e62..0f423e2 100755 --- a/light.cpp +++ b/light.cpp @@ -75,32 +75,39 @@ namespace vb01{ glBindFramebuffer(GL_FRAMEBUFFER, *(Root::getSingleton()->getFBO())); } - void Light::update(){ + void Light::update(bool render){ Root *root = Root::getSingleton(); Node *rootNode = root->getRootNode(); vector descendants; rootNode->getDescendants(descendants); descendants.push_back(rootNode); + vector lights; vector materials; for(Node *d : descendants){ for(Light *l : d->getLights()) lights.push_back(l); - for(Mesh *m : d->getMeshes()) - materials.push_back(m->getMaterial()); + for(Mesh *mesh : d->getMeshes()) + materials.push_back(mesh->getMaterial()); } int thisId = -1; + for(int i = 0; i < lights.size(); i++) if(lights[i] == this) thisId = i; + for(Material *mat : materials){ + Shader *shader = mat->getShader(); + shader->use(); + shader->setBool(render, "lights[" + to_string(thisId) + "].render"); + } + mat4 proj = mat4(1.), view = mat4(1.); renderShadow(descendants, proj, view); updateShader(materials, thisId, proj, view); - } void Light::renderShadow(std::vector descendants, mat4 &proj, mat4 &view){ @@ -176,8 +183,10 @@ namespace vb01{ glViewport(0, 0, root->getWidth(), root->getHeight()); } + //TODO replace depth map id literals void Light::updateShader(vector materials, int thisId, mat4 &proj, mat4 &view){ Vector3 position = node->localToGlobalPosition(Vector3::VEC_ZERO), direction = node->getGlobalAxis(2); + for(Material *m : materials){ Shader *shader = m->getShader(); shader->use(); @@ -185,6 +194,7 @@ namespace vb01{ shader->setVec3(color, "lights[" + to_string(thisId) + "].color"); shader->setFloat(nearPlane, "lights[" + to_string(thisId) + "].near"); shader->setFloat(farPlane, "lights[" + to_string(thisId) + "].far"); + shader->setBool(additiveLighting, "lights[" + to_string(thisId) + "].additive"); int depthMapId = 10; shader->setInt(depthMapId, "lights[" + to_string(thisId) + "].depthMap"); @@ -194,9 +204,12 @@ namespace vb01{ switch(type){ case POINT: shader->setVec3(position, "lights[" + to_string(thisId) + "].pos"); + shader->setInt((int)attenuation, "lights[" + to_string(thisId) + "].attenuation"); + shader->setFloat(radius, "lights[" + to_string(thisId) + "].radius"); shader->setFloat(attenuationValues.x, "lights[" + to_string(thisId) + "].a"); shader->setFloat(attenuationValues.y, "lights[" + to_string(thisId) + "].b"); shader->setFloat(attenuationValues.z, "lights[" + to_string(thisId) + "].c"); + shader->setBool(useAngle, "lights[" + to_string(thisId) + "].useAngle"); break; case DIRECTIONAL: shader->setMat4(proj * view, "lights[" + to_string(thisId) + "].lightMat"); diff --git a/light.h b/light.h index 1732d94..9fe4424 100755 --- a/light.h +++ b/light.h @@ -17,10 +17,13 @@ namespace vb01{ class Light : public Animatable, public Attachable{ public: enum Type{POINT, DIRECTIONAL, SPOT, AMBIENT}; + enum Attenuation{QUADRATIC, LINEAR, NONE}; Light(Type, std::string = ""); ~Light(); - void update(); + void update(bool); + inline Vector3 getColor(){return color;} + inline Type getLightType(){return type;} inline void setColor(Vector3 color){this->color = color;} inline void setAttenuationValues(float a, float b, float c){ attenuationValues.x = a; @@ -31,7 +34,14 @@ namespace vb01{ inline void setOuterAngle(float outerAngle){this->outerAngle = outerAngle;} inline void setShadowNearPlane(float nearPlane){this->nearPlane = nearPlane;} inline void setShadowFarPlane(float farPlane){this->farPlane = farPlane;} + inline void setAttenuation(Attenuation at){this->attenuation = at;} + inline void setRadius(float r){this->radius = r;} + inline void setAdditiveLighting(bool al){this->additiveLighting = al;} + inline void setUseAngle(bool ua){this->useAngle = ua;} + inline Attenuation getAttenuation(){return attenuation;} inline Vector3 getAttenuationValues(){return attenuationValues;} + inline bool isAdditiveLighting(){return additiveLighting;} + inline float getRadius(){return radius;} inline float getInnerAngle(){return innerAngle;} inline float getOuterAngle(){return outerAngle;} inline float getShadowNearPlane(){return nearPlane;} @@ -43,10 +53,12 @@ namespace vb01{ void updateShader(std::vector, int, glm::mat4&, glm::mat4&); Type type; + bool additiveLighting = true, useAngle = true; + Attenuation attenuation = Attenuation::QUADRATIC; Shader *depthMapShader; Texture *depthMap = nullptr; Vector3 color = Vector3::VEC_IJK, attenuationValues = Vector3(1.8, .7, 1); - float innerAngle = .707, outerAngle = .714, nearPlane = .1, farPlane = 100; + float innerAngle = .707, outerAngle = .714, nearPlane = .1, farPlane = 100, radius = 0; unsigned int depthmapFBO, depthMapSize = 1024; }; } diff --git a/mesh.cpp b/mesh.cpp index c8c8a25..64de30e 100755 --- a/mesh.cpp +++ b/mesh.cpp @@ -44,31 +44,35 @@ namespace vb01{ glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); - u32 size = sizeof(MeshData::Vertex); + u32 size = sizeof(MeshData::GpuVertex); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, 3 * meshBase.numTris * size, meshBase.vertices, GL_DYNAMIC_DRAW); + + MeshData::GpuVertex *glVertData = meshBase.toGpuVerts(); + glBufferData(GL_ARRAY_BUFFER, 3 * meshBase.numTris * size, glVertData, GL_DYNAMIC_DRAW); + delete glVertData; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * meshBase.numTris * sizeof(u32), meshBase.indices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, size, (void*)0); glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, norm))); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, norm))); glEnableVertexAttribArray(1); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, uv))); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, uv))); glEnableVertexAttribArray(2); - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, tan))); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, tan))); glEnableVertexAttribArray(3); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, biTan))); + glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, biTan))); glEnableVertexAttribArray(4); - glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, weights))); + glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, weights))); glEnableVertexAttribArray(5); - glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, boneIndices))); + glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, boneIndices))); glEnableVertexAttribArray(6); for(int i = 0; i < meshBase.numShapeKeys; i++){ - glVertexAttribPointer(7 + i, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::Vertex, shapeKeyOffsets) + 3 * i * sizeof(float))); + glVertexAttribPointer(7 + i, 3, GL_FLOAT, GL_FALSE, size, (void*)(offsetof(MeshData::GpuVertex, shapeKeyOffsets) + 3 * i * sizeof(float))); glEnableVertexAttribArray(7 + i); } } @@ -91,7 +95,10 @@ namespace vb01{ void Mesh::updateVerts(MeshData meshData){ glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferSubData(GL_ARRAY_BUFFER, 0, 3 * sizeof(MeshData::Vertex) * meshBase.numTris, meshData.vertices); + + MeshData::GpuVertex *glVertData = meshBase.toGpuVerts(); + glBufferSubData(GL_ARRAY_BUFFER, 0, 3 * sizeof(MeshData::GpuVertex) * meshBase.numTris, glVertData); + delete glVertData; } void Mesh::update(){ diff --git a/meshData.cpp b/meshData.cpp index b5223c9..ba7572b 100644 --- a/meshData.cpp +++ b/meshData.cpp @@ -17,22 +17,29 @@ namespace vb01{ } } - MeshData::ShapeKey::ShapeKey(string name, float value, float minValue, float maxValue) : Animatable(Animatable::SHAPE_KEY, name){ - this->name = name; - this->value = value; - this->minValue = minValue; - this->maxValue = maxValue; - } + MeshData::GpuVertex* MeshData::toGpuVerts(){ + int numVertices = 3 * numTris; + GpuVertex *vertData = new GpuVertex[numVertices]; - MeshData::MeshData(Vertex *vertices, u32 *indices, int numTris, string attachableName, string *vertexGroups, int numVertexGroups, string fullSkeletonName, ShapeKey *shapeKeys, int numShapeKeys){ - this->vertices = vertices; - this->indices = indices; - this->numTris = numTris; - this->attachableName = attachableName; - this->vertexGroups = vertexGroups; - this->numVertexGroups = numVertexGroups; - this->fullSkeletonName = fullSkeletonName; - this->shapeKeys = shapeKeys; - this->numShapeKeys = numShapeKeys; + for(int i = 0; i < numVertices; i++){ + vertData[i].pos = *vertices[i].pos; + vertData[i].norm = *vertices[i].norm; + vertData[i].tan = vertices[i].tan; + vertData[i].biTan = vertices[i].biTan; + vertData[i].uv = vertices[i].uv; + + if(weights){ + for(int j = 0; j < 4; j++){ + vertData[i].weights[j] = vertices[i].weights[j]; + vertData[i].boneIndices[j] = vertices[i].boneIndices[j]; + } + } + + if(shapeKeyOffsets) + for(int j = 0; j < 100; j++) + vertData[i].shapeKeyOffsets[j] = vertices[i].shapeKeyOffsets[j]; + } + + return vertData; } } diff --git a/meshData.h b/meshData.h index 783f60d..6ca0ced 100644 --- a/meshData.h +++ b/meshData.h @@ -14,12 +14,12 @@ namespace vb01{ std::string name; float minValue, value, maxValue; - ShapeKey(std::string, float, float, float); + ShapeKey(std::string n, float v, float mnv, float mxv) : name(n), value(v), minValue(mnv), maxValue(mxv), Animatable(Animatable::SHAPE_KEY, n){} ShapeKey() : Animatable(Animatable::SHAPE_KEY){} void animate(float, KeyframeChannel); }; - struct Vertex{ + struct GpuVertex{ Vector3 pos, norm, tan, biTan; Vector2 uv; float weights[4]{0, 0, 0, 0}; @@ -27,15 +27,43 @@ namespace vb01{ Vector3 shapeKeyOffsets[100]; }; + struct Vertex{ + Vector3 *pos = nullptr, *norm = nullptr, tan, biTan; + Vector2 uv; + float *weights = nullptr; + int *boneIndices = nullptr; + Vector3 *shapeKeyOffsets = nullptr; + }; + + GpuVertex* toGpuVerts(); + + Vector3 *positions = nullptr, *normals = nullptr, **shapeKeyOffsets = nullptr; + float **weights = nullptr; + int **boneIndices = nullptr; Vertex *vertices; std::string *vertexGroups = nullptr; ShapeKey *shapeKeys = nullptr; u32 *indices, VAO, VBO, EBO; - int numTris, numVertexGroups = 0, numShapeKeys = 0; + int numPos, numTris, numVertexGroups = 0, numShapeKeys = 0; std::string attachableName = "", fullSkeletonName = ""; MeshData(){} - MeshData(Vertex*, u32*, int, std::string = "", std::string *vg = nullptr, int = 0, std::string = "", ShapeKey *sk = nullptr, int = 0); + MeshData(Vector3 *pos, float **w, int **bi, Vector3 **sko, int np, Vector3 *norm, Vertex *vert, u32 *ind, int nt, std::string an = "", std::string *vg = nullptr, int nvg = 0, std::string fsn = "", ShapeKey *sk = nullptr, int nsk = 0) : + positions(pos), + weights(w), + boneIndices(bi), + shapeKeyOffsets(sko), + numPos(np), + normals(norm), + vertices(vert), + indices(ind), + numTris(nt), + vertexGroups(vg), + numVertexGroups(nvg), + fullSkeletonName(fsn), + shapeKeys(sk), + numShapeKeys(nsk) + {} }; } diff --git a/model.cpp b/model.cpp index a98cf93..8d5f46a 100755 --- a/model.cpp +++ b/model.cpp @@ -28,8 +28,6 @@ namespace vb01{ } Model::~Model(){ - delete children[0]->getMesh(0)->getMaterial(); - vector descendants; getDescendants(descendants); diff --git a/node.cpp b/node.cpp index d57cd3e..7b3a5f7 100755 --- a/node.cpp +++ b/node.cpp @@ -1,12 +1,15 @@ #include "root.h" #include "bone.h" #include "mesh.h" -#include "particleEmitter.h" -#include "light.h" #include "text.h" -#include "material.h" +#include "util.h" +#include "light.h" #include "matrix.h" +#include "material.h" #include "skeleton.h" +#include "shaderAsset.h" +#include "particleEmitter.h" +#include "assetManager.h" #include "animationController.h" #include @@ -53,10 +56,10 @@ namespace vb01{ if(!render) break; } - if(render){ - for(Light *l : lights) - l->update(); + for(Light *l : lights) + l->update(render); + if(render){ for(Mesh *m : meshes) m->update(); @@ -245,6 +248,19 @@ namespace vb01{ lights.push_back(light); light->onAttached(this); updateShaders(); + + } + + void Node::removeLight(Light *light){ + for(int i = 0; i < lights.size(); i++) + if(lights[i] == light){ + lights.erase(lights.begin() + i); + + Root::getSingleton()->shiftNumLights(false); + updateShaders(); + + break; + } } void Node::removeLight(int id){ @@ -439,27 +455,23 @@ namespace vb01{ void Node::updateShaders(){ Root *root = Root::getSingleton(); + AssetManager *am = AssetManager::getSingleton(); + ShaderAsset *sa = (ShaderAsset*)am->getAsset(root->getLibPath() + "texture.frag"); + string shaderStr = sa->shaderString; + int numLights = root->getNumLights(); - Node *rootNode = root->getRootNode(); - vector descendants; - rootNode->getDescendants(descendants); - descendants.push_back(rootNode); + string str1 = "const int numLights = " + to_string(numLights > 0 ? numLights : 1) + ";"; + int a1 = findNthOccurence(shaderStr, "\n", 0); + int a2 = findNthOccurence(shaderStr, "\n", 1); + shaderStr.replace(a1 + 1, a2 - a1 - 1, str1); - for(Node *n : descendants){ - vector meshes = n->getMeshes(); + string str2 = "const bool checkLights = " + string(numLights > 0 ? "true" : "false") + ";"; + a1 = findNthOccurence(shaderStr, "\n", 1); + a2 = findNthOccurence(shaderStr, "\n", 2); + shaderStr.replace(a1 + 1, a2 - a1 - 1, str2); - for(Mesh *m : meshes){ - Material *mat = m->getMaterial(); - - if(mat){ - int numLights = root->getNumLights(); - string str1 = "const int numLights = " + to_string(numLights > 0 ? numLights : 1) + ";"; - mat->getShader()->editShader(Shader::FRAGMENT_SHADER, 1, str1); - string str2 = "const bool checkLights = " + string(numLights > 0 ? "true" : "false") + ";"; - mat->getShader()->editShader(Shader::FRAGMENT_SHADER, 2, str2); - } - } - } + ShaderAsset sa2(sa->path, shaderStr); + am->editAsset(sa->path, sa2); } void Node::setOrientation(Quaternion q){ diff --git a/node.h b/node.h index bce352c..46aec28 100755 --- a/node.h +++ b/node.h @@ -31,6 +31,7 @@ namespace vb01{ void attachChild(Node*); void dettachChild(Node*); void addLight(Light*); + void removeLight(Light*); void removeLight(int); void addText(Text*); virtual void lookAt(Vector3, Vector3); diff --git a/quad.cpp b/quad.cpp index 3181479..076b313 100755 --- a/quad.cpp +++ b/quad.cpp @@ -1,6 +1,10 @@ #include "quad.h" +#include + namespace vb01{ + using namespace std; + Quad::Quad(Vector3 size, bool spatial, int numVertDiv, int numHorDiv){ this->spatial = spatial; this->numVertDiv = numVertDiv; @@ -14,55 +18,72 @@ namespace vb01{ this->size = size; const int numHorQuads = numVertDiv + 1, numVertQuads = numHorDiv + 1; - const int numTris = 2 * numHorQuads * numVertQuads, numVerts = 3 * numTris; + const int numVertPos = (numHorQuads + 1) * (numVertQuads + 1), numTris = 2 * numHorQuads * numVertQuads, numVerts = 3 * numTris; Vector2 subQuadSize = Vector2(size.x / numHorQuads, size.y / numVertQuads); MeshData::Vertex *vertices = new MeshData::Vertex[numVerts]; + if(!meshBase.positions){ + meshBase.positions = new Vector3[numVertPos]; + meshBase.normals = new Vector3(Vector3::VEC_J); + meshBase.indices = new u32[numVerts]; + + for(int i = 0; i < numVerts; i++) + meshBase.indices[i] = i; + } + + Vector3 *faceVertPos = meshBase.positions; + Vector3 *norm = meshBase.normals; + u32 *indices = meshBase.indices; + for(int i = 0; i < numHorQuads; i++){ for(int j = 0; j < numVertQuads; j++){ - int id = i * 6 * numHorQuads + j * 6; + int vertPosId = i * (numHorQuads + 1) + j; + int vertPosId2 = (i + 1) * (numHorQuads + 1) + j; Vector2 offset = Vector2(subQuadSize.x, subQuadSize.y); - Vector3 faceVertPos[]{ - Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * i), - Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * (i + 1)), - Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * i), - Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * i), - Vector3(-.5 * size.x + offset.x * j, 0, -.5 * size.y + offset.y * (i + 1)), - Vector3(-.5 * size.x + offset.x * (j + 1), 0, -.5 * size.y + offset.y * (i + 1)) - }; + + faceVertPos[vertPosId] = Vector3(-.5 * size.x + offset.x * i, 0, -.5 * size.y + offset.y * j); + faceVertPos[vertPosId + 1] = Vector3(-.5 * size.x + offset.x * i, 0, -.5 * size.y + offset.y * (j + 1)); + faceVertPos[vertPosId2] = Vector3(-.5 * size.x + offset.x * (i + 1), 0, -.5 * size.y + offset.y * j); + faceVertPos[vertPosId2 + 1] = Vector3(-.5 * size.x + offset.x * (i + 1), 0, -.5 * size.y + offset.y * (j + 1)); + + if(!spatial){ + int ids[4]{vertPosId, vertPosId + 1, vertPosId2, vertPosId2 + 1}; + + swap(faceVertPos[ids[0]].z, faceVertPos[ids[1]].z); + swap(faceVertPos[ids[2]].z, faceVertPos[ids[3]].z); + + for(int k = 0; k < 4; k++){ + faceVertPos[ids[k]].y = -faceVertPos[ids[k]].z; + faceVertPos[ids[k]].z = 0; + faceVertPos[ids[k]] += .5 * Vector3(size.x, size.y, 0); + } + } + Vector2 faceVertUv[]{ - Vector2(float(j) / numHorQuads, float(i) / numVertQuads), - Vector2(float(j + 1) / numHorQuads, float(i + 1) / numVertQuads), - Vector2(float(j + 1) / numHorQuads, float(i) / numVertQuads), - Vector2(float(j) / numHorQuads, float(i) / numVertQuads), - Vector2(float(j) / numHorQuads, float(i + 1) / numVertQuads), - Vector2(float(j + 1) / numHorQuads, float(i + 1) / numVertQuads), + Vector2(float(i) / numHorQuads, 1 - float(j) / numVertQuads), + Vector2(float(i) / numHorQuads, 1 - float(j + 1) / numVertQuads), + Vector2(float(i + 1) / numHorQuads, 1 - float(j + 1) / numVertQuads), + Vector2(float(i + 1) / numHorQuads, 1 - float(j + 1) / numVertQuads), + Vector2(float(i + 1) / numHorQuads, 1 - float(j) / numVertQuads), + Vector2(float(i) / numHorQuads, 1 - float(j) / numVertQuads), }; + int quadId = 6 * (i * numHorQuads + j); + int vertPosIds[6]{vertPosId, vertPosId + 1, vertPosId2 + 1, vertPosId2 + 1, vertPosId2, vertPosId}; + for(int k = 0; k < 6; k++){ - if(!spatial){ - faceVertPos[k].y = -faceVertPos[k].z; - faceVertPos[k].z = 0; - faceVertPos[k] += .5 * Vector3(size.x, size.y, 0); - } - MeshData::Vertex v; - v.pos = faceVertPos[k]; + v.pos = &faceVertPos[vertPosIds[k]]; v.uv = faceVertUv[k]; v.tan = Vector3::VEC_I; - v.norm = Vector3::VEC_J; + v.norm = norm; v.biTan = Vector3::VEC_K; - vertices[id + k] = v; + vertices[quadId + k] = v; } } } - u32 *indices = new u32[numVerts]; - - for(int i = 0; i < numVerts; i++) - indices[i] = i; - - meshBase = MeshData(vertices, indices, numTris); + meshBase = MeshData(faceVertPos, nullptr, nullptr, nullptr, 6, norm, vertices, indices, numTris); } } diff --git a/rayCaster.cpp b/rayCaster.cpp index 43e09df..dc6f6d2 100644 --- a/rayCaster.cpp +++ b/rayCaster.cpp @@ -42,7 +42,7 @@ namespace vb01{ bool skip = false; for(int j = 0; j < 3; j++){ - Vector3 rayPosToVert = (vertices[i * 3 + j].pos - rayPos); + Vector3 rayPosToVert = (*(vertices[i * 3 + j].pos) - rayPos); float angle = rayDir.getAngleBetween(rayPosToVert.norm()); if(angle > PI / 2) angle = PI - angle; @@ -58,7 +58,7 @@ namespace vb01{ if(skip) continue; } - Vector3 pointA = pos + rot * vertices[indices[i * 3]].pos, pointB = pos + rot * vertices[indices[i * 3 + 1]].pos, pointC = pos + rot * vertices[indices[i * 3 + 2]].pos; + Vector3 pointA = pos + rot * *(vertices[indices[i * 3]].pos), pointB = pos + rot * *(vertices[indices[i * 3 + 1]].pos), pointC = pos + rot * *(vertices[indices[i * 3 + 2]].pos); Vector3 hypVec = pointA - rayPos; Vector3 perpVec = (pointB - pointA).cross(pointC - pointA).norm(); float a1 = hypVec.norm().getAngleBetween(perpVec); diff --git a/root.cpp b/root.cpp index 01bb698..0c0c1d5 100755 --- a/root.cpp +++ b/root.cpp @@ -5,6 +5,7 @@ #include "box.h" #include "quad.h" #include "lineRenderer.h" +#include "assetManager.h" #include "animationController.h" #include "glad.h" @@ -22,6 +23,7 @@ namespace vb01{ Root* Root::getSingleton(){ if(!root) root = new Root(); + return root; } @@ -47,6 +49,8 @@ namespace vb01{ this->height = height; this->libPath = libPath; + AssetManager::getSingleton()->load(Root::getSingleton()->getLibPath()); + initWindow(name); brdfLutPlane = new Quad(Vector3(1, 1, 1) * 2); @@ -59,7 +63,7 @@ namespace vb01{ initBloomFramebuffer(); initGuiPlane(fragTexture, brightTexture); - shader = new Shader(Root::getSingleton()->getLibPath() + "line3D"); + shader = new Shader(Root::getSingleton()->getLibPath() + "line3D"); } void Root::initWindow(string name){ diff --git a/samples/models/kek.xml b/samples/models/kek.xml index 25080a7..a510627 100644 --- a/samples/models/kek.xml +++ b/samples/models/kek.xml @@ -1,6 +1,6 @@ - - + + @@ -144,9 +144,9 @@ - - - + + + @@ -162,7 +162,7 @@ - + @@ -178,7 +178,7 @@ - + @@ -194,7 +194,7 @@ - + @@ -210,7 +210,7 @@ - + @@ -226,7 +226,7 @@ - + @@ -242,7 +242,7 @@ - + @@ -258,7 +258,7 @@ - + @@ -274,7 +274,7 @@ - + @@ -290,7 +290,7 @@ - + @@ -306,7 +306,7 @@ - + @@ -322,7 +322,7 @@ - + @@ -338,7 +338,7 @@ - + @@ -354,7 +354,7 @@ - + @@ -370,7 +370,7 @@ - + @@ -386,7 +386,7 @@ - + @@ -402,7 +402,7 @@ - + @@ -418,7 +418,7 @@ - + @@ -434,7 +434,7 @@ - + @@ -450,7 +450,7 @@ - + @@ -466,7 +466,7 @@ - + @@ -482,7 +482,7 @@ - + @@ -498,7 +498,7 @@ - + @@ -514,7 +514,7 @@ - + @@ -530,7 +530,7 @@ - + @@ -546,7 +546,7 @@ - + @@ -562,7 +562,7 @@ - + @@ -578,7 +578,7 @@ - + @@ -594,7 +594,7 @@ - + @@ -610,7 +610,7 @@ - + @@ -626,7 +626,7 @@ - + @@ -642,7 +642,7 @@ - + @@ -658,7 +658,7 @@ - + @@ -674,7 +674,7 @@ - + @@ -690,7 +690,7 @@ - + @@ -706,7 +706,7 @@ - + @@ -722,7 +722,7 @@ - + @@ -738,7 +738,7 @@ - + @@ -754,7 +754,7 @@ - + @@ -770,7 +770,7 @@ - + @@ -786,7 +786,7 @@ - + @@ -802,7 +802,7 @@ - + @@ -818,7 +818,7 @@ - + @@ -834,7 +834,7 @@ - + @@ -850,7 +850,7 @@ - + @@ -866,7 +866,7 @@ - + @@ -882,7 +882,7 @@ - + @@ -898,7 +898,7 @@ - + @@ -914,7 +914,7 @@ - + @@ -930,7 +930,7 @@ - + @@ -946,7 +946,7 @@ - + @@ -962,7 +962,7 @@ - + @@ -978,7 +978,7 @@ - + @@ -994,7 +994,7 @@ - + @@ -1010,7 +1010,7 @@ - + @@ -1026,7 +1026,7 @@ - + @@ -1042,7 +1042,7 @@ - + @@ -1058,7 +1058,7 @@ - + @@ -1074,7 +1074,7 @@ - + @@ -1090,7 +1090,7 @@ - + @@ -1106,7 +1106,7 @@ - + @@ -1122,7 +1122,7 @@ - + @@ -1138,7 +1138,7 @@ - + @@ -1154,7 +1154,7 @@ - + @@ -1170,7 +1170,7 @@ - + @@ -1186,7 +1186,7 @@ - + @@ -1202,7 +1202,7 @@ - + @@ -1218,7 +1218,7 @@ - + @@ -1234,7 +1234,7 @@ - + @@ -1250,7 +1250,7 @@ - + @@ -1266,7 +1266,7 @@ - + @@ -1282,7 +1282,7 @@ - + @@ -1298,7 +1298,7 @@ - + @@ -1314,7 +1314,7 @@ - + @@ -1330,7 +1330,7 @@ - + @@ -1346,7 +1346,7 @@ - + @@ -1362,7 +1362,7 @@ - + @@ -1378,7 +1378,7 @@ - + @@ -1394,7 +1394,7 @@ - + @@ -1410,7 +1410,7 @@ - + @@ -1426,7 +1426,7 @@ - + @@ -1442,7 +1442,7 @@ - + @@ -1458,7 +1458,7 @@ - + @@ -1474,7 +1474,7 @@ - + @@ -1490,7 +1490,7 @@ - + @@ -1506,7 +1506,7 @@ - + @@ -1522,7 +1522,7 @@ - + @@ -1538,7 +1538,7 @@ - + @@ -1554,7 +1554,7 @@ - + @@ -1570,7 +1570,7 @@ - + @@ -1586,7 +1586,7 @@ - + @@ -1602,7 +1602,7 @@ - + @@ -1618,7 +1618,7 @@ - + @@ -1634,7 +1634,7 @@ - + @@ -1650,7 +1650,7 @@ - + @@ -1666,7 +1666,7 @@ - + @@ -1682,7 +1682,7 @@ - + @@ -1698,7 +1698,7 @@ - + @@ -1714,7 +1714,7 @@ - + @@ -1730,7 +1730,7 @@ - + @@ -1746,7 +1746,7 @@ - + @@ -1762,7 +1762,7 @@ - + @@ -1778,7 +1778,7 @@ - + @@ -1794,7 +1794,7 @@ - + @@ -1810,7 +1810,7 @@ - + @@ -1826,7 +1826,7 @@ - + @@ -1842,7 +1842,7 @@ - + @@ -1858,7 +1858,7 @@ - + @@ -1874,7 +1874,7 @@ - + @@ -1890,7 +1890,7 @@ - + @@ -1906,7 +1906,7 @@ - + @@ -1922,7 +1922,7 @@ - + @@ -1938,7 +1938,7 @@ - + @@ -1954,7 +1954,7 @@ - + @@ -1970,7 +1970,7 @@ - + @@ -1986,7 +1986,7 @@ - + @@ -2002,7 +2002,7 @@ - + @@ -2018,7 +2018,7 @@ - + @@ -2034,7 +2034,7 @@ - + @@ -2050,7 +2050,7 @@ - + @@ -2066,7 +2066,7 @@ - + @@ -2082,7 +2082,7 @@ - + @@ -2098,7 +2098,7 @@ - + @@ -2114,7 +2114,7 @@ - + @@ -2130,7 +2130,7 @@ - + @@ -2146,7 +2146,7 @@ - + @@ -2162,7 +2162,7 @@ - + @@ -2178,7 +2178,7 @@ - + @@ -2194,7 +2194,7 @@ - + @@ -2210,7 +2210,7 @@ - + @@ -2226,7 +2226,7 @@ - + @@ -2242,7 +2242,7 @@ - + @@ -2258,7 +2258,7 @@ - + @@ -2274,7 +2274,7 @@ - + @@ -2290,7 +2290,7 @@ - + @@ -2306,7 +2306,7 @@ - + @@ -2322,7 +2322,7 @@ - + @@ -2338,7 +2338,7 @@ - + @@ -2354,7 +2354,7 @@ - + @@ -2370,7 +2370,7 @@ - + @@ -2386,7 +2386,7 @@ - + @@ -2402,7 +2402,7 @@ - + @@ -2418,7 +2418,7 @@ - + @@ -2434,7 +2434,7 @@ - + @@ -2450,7 +2450,7 @@ - + @@ -2466,7 +2466,7 @@ - + @@ -2482,7 +2482,7 @@ - + @@ -2498,7 +2498,7 @@ - + @@ -2514,7 +2514,7 @@ - + @@ -2530,7 +2530,7 @@ - + @@ -2546,7 +2546,7 @@ - + @@ -2562,7 +2562,7 @@ - + @@ -2578,7 +2578,7 @@ - + @@ -2594,7 +2594,7 @@ - + @@ -2610,7 +2610,7 @@ - + @@ -2626,7 +2626,7 @@ - + @@ -2642,7 +2642,7 @@ - + @@ -2658,7 +2658,7 @@ - + @@ -2674,7 +2674,7 @@ - + @@ -2690,7 +2690,7 @@ - + @@ -2706,7 +2706,7 @@ - + @@ -2722,7 +2722,7 @@ - + @@ -2738,7 +2738,7 @@ - + @@ -2754,7 +2754,7 @@ - + @@ -2770,7 +2770,7 @@ - + @@ -2786,7 +2786,7 @@ - + @@ -2802,7 +2802,7 @@ - + @@ -2818,7 +2818,7 @@ - + @@ -2834,7 +2834,7 @@ - + @@ -2850,7 +2850,7 @@ - + @@ -2866,7 +2866,7 @@ - + @@ -2882,7 +2882,7 @@ - + @@ -2898,7 +2898,7 @@ - + @@ -2914,7 +2914,7 @@ - + @@ -2930,7 +2930,7 @@ - + @@ -2946,7 +2946,7 @@ - + @@ -2962,7 +2962,7 @@ - + @@ -2978,7 +2978,7 @@ - + @@ -2994,7 +2994,7 @@ - + @@ -3010,7 +3010,7 @@ - + @@ -3026,7 +3026,7 @@ - + @@ -3042,7 +3042,7 @@ - + @@ -3058,7 +3058,7 @@ - + @@ -3074,7 +3074,7 @@ - + @@ -3090,7 +3090,7 @@ - + @@ -3106,7 +3106,7 @@ - + @@ -3122,7 +3122,7 @@ - + @@ -3138,7 +3138,7 @@ - + @@ -3154,7 +3154,7 @@ - + @@ -3170,7 +3170,7 @@ - + @@ -3186,7 +3186,7 @@ - + @@ -3202,7 +3202,7 @@ - + @@ -3218,7 +3218,7 @@ - + @@ -3234,7 +3234,7 @@ - + @@ -3250,7 +3250,7 @@ - + @@ -3266,7 +3266,7 @@ - + @@ -3282,7 +3282,7 @@ - + @@ -3298,7 +3298,7 @@ - + @@ -3314,7 +3314,7 @@ - + @@ -3330,7 +3330,7 @@ - + @@ -3346,7 +3346,7 @@ - + @@ -3362,7 +3362,7 @@ - + @@ -3378,7 +3378,7 @@ - + @@ -3394,7 +3394,7 @@ - + @@ -3410,7 +3410,7 @@ - + @@ -3426,7 +3426,7 @@ - + @@ -3442,7 +3442,7 @@ - + @@ -3458,7 +3458,7 @@ - + @@ -3474,7 +3474,7 @@ - + @@ -3490,7 +3490,7 @@ - + @@ -3506,7 +3506,7 @@ - + @@ -3522,7 +3522,7 @@ - + @@ -3538,7 +3538,7 @@ - + @@ -3554,7 +3554,7 @@ - + @@ -3570,7 +3570,7 @@ - + @@ -3586,7 +3586,7 @@ - + @@ -3602,7 +3602,7 @@ - + @@ -3618,7 +3618,7 @@ - + @@ -3634,7 +3634,7 @@ - + @@ -3650,7 +3650,7 @@ - + @@ -3666,7 +3666,7 @@ - + @@ -3682,7 +3682,7 @@ - + @@ -3698,7 +3698,7 @@ - + @@ -3714,7 +3714,7 @@ - + @@ -3730,7 +3730,7 @@ - + @@ -3746,7 +3746,7 @@ - + @@ -3762,7 +3762,7 @@ - + @@ -3778,7 +3778,7 @@ - + @@ -3794,7 +3794,7 @@ - + @@ -3810,7 +3810,7 @@ - + @@ -3826,7 +3826,7 @@ - + @@ -3842,7 +3842,7 @@ - + @@ -3858,7 +3858,7 @@ - + @@ -3874,7 +3874,7 @@ - + @@ -3890,7 +3890,7 @@ - + @@ -3906,7 +3906,7 @@ - + @@ -3922,7 +3922,7 @@ - + @@ -3938,7 +3938,7 @@ - + @@ -3954,7 +3954,7 @@ - + @@ -3970,7 +3970,7 @@ - + @@ -3986,7 +3986,7 @@ - + @@ -4002,7 +4002,7 @@ - + @@ -4018,7 +4018,7 @@ - + @@ -4034,7 +4034,7 @@ - + @@ -4050,7 +4050,7 @@ - + @@ -4066,7 +4066,7 @@ - + @@ -4082,7 +4082,7 @@ - + @@ -4098,7 +4098,7 @@ - + @@ -4114,7 +4114,7 @@ - + @@ -4130,7 +4130,7 @@ - + @@ -4146,7 +4146,7 @@ - + @@ -4162,7 +4162,7 @@ - + @@ -4178,7 +4178,7 @@ - + @@ -4194,7 +4194,7 @@ - + @@ -4210,7 +4210,7 @@ - + @@ -4226,7 +4226,7 @@ - + @@ -4256,61 +4256,61 @@ - - + + - - + + - - + + - - + + - + - - + + - - - + + + - - - + + + - - - - - + + + + + - - + + - + - + - + @@ -4325,311 +4325,311 @@ - - + + - + - + - - + + - + - + - + - + - - + + - + - - + + - + - + - - + + - + - - - - + + + + - - + + - + - - - - - - + + + + + + - - + + - - + + - - - + + + - - - - - - - - - - - + + + + + + + + + + + - - + + - - + + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - - - + + + + - - + + - + - - + + - - + + - - + + - + - + - - + + - - + + - - - - + + + + - + - - + + - - + + - + - - + + - - + + - - + + - - - - - + + + + + - - + + - + - - + + - + - - + + - - - - - + + + + + - - - - - + + + + + - - + + - + - - - - - + + + + + - + - + - + - + - + - - + + - + - - + + - + - + @@ -4642,18 +4642,18 @@ - - - + + + - - + + - + - + @@ -4679,8 +4679,8 @@ - - + + @@ -4688,351 +4688,351 @@ - - + + - - + + - - + + - + - + - + - + - - + + - - + + - + - + - - + + - + - - - - + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - + + - - - - - - - - + + + + + + + + - - + + - + - + - - + + - - + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - + + - - + + - - - - - - - - + + + + + + + + - - + + - - + + - - + + - + - + - + - + - + - - + + - - + + - + - - - - + + + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - - - + + + + - - + + - + - - + + - - + + - - + + - - + + - + - - - - + + + + - + - - + + - - - - + + + + - - + + - + - - - - + + + + - + - - + + - - + + - - + + - + - + - - + + - + - + - + - + - + - - - - - + + + + + - + - - - - + + + + - - + + - - + + - + @@ -5041,8 +5041,8 @@ - - + + @@ -5057,312 +5057,312 @@ - + - - + + - + - + - - + + - + - + - + - + - - + + - + - - + + - + - + - + - - - + + + - + - + - - + + - - + + - - - - - + + + + + - + - + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - + + - - - - - - - - + + + + + + + + - - - - + + + + - - - - - + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + - - + + - - + + - - + + - + - + - + - + - + - + - + - - + + - + - + - - - + + + - - + + - + - + - + - + - + - - + + - - + + - + - + - + - - - + + + - + - + - + - - + + - - + + - - + + - - - - - + + + + + - + - - + + - - - - + + + + - + - + - - + + - - + + - + - + - + - + - + - + @@ -5375,18 +5375,18 @@ - + - - + + - - - + + + - + @@ -5411,315 +5411,315 @@ - + - + - + - - + + - - + + - + - + - + - + - + - - + + - - + + - + - + - + - - - + + + - + - - - + + + - + - - - - + + + + - - + + - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - + + + + + - - + + - - + + - - - - - - - - - - - + + + + + + + + + + + - - + + - - + + - - - - - + + + + + - - + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - + + - - + + - - + + - + - - + + - + - + - + - + - + - + - - + + - - + + - - + + - - - + + + - + - - + + - - + + - + - - - + + + - - + + - + - - + + - + - - + + - - + + - + - + - - + + - - + + - + - - + + - + - + - - - + + + - + - - + + - - - - - + + + + + - - + + - + - - + + - + - - + + - + - + - + - + @@ -6251,4 +6251,4 @@ - \ No newline at end of file + diff --git a/script.py b/script.py index 5af0a9a..a7a85e7 100644 --- a/script.py +++ b/script.py @@ -166,6 +166,7 @@ def export(node, parentTag): if node.type == 'MESH': mesh = node.data + numVertexPos = len(mesh.vertices) numFaces = len(mesh.polygons) numVerts = len(mesh.vertices) numGroups = len(node.vertex_groups) @@ -176,6 +177,7 @@ def export(node, parentTag): meshTag = ET.SubElement(nodeTag, 'mesh') meshTag.set('name', node.name + mesh.name_full) + meshTag.set('num_vertex_pos', str(numVertexPos)) meshTag.set('num_faces', str(numFaces)) meshTag.set('num_vertex_groups', str(numGroups)) meshTag.set('num_shape_keys', str(numShapeKeys)) diff --git a/shader.cpp b/shader.cpp index 79e6035..4a63f0c 100755 --- a/shader.cpp +++ b/shader.cpp @@ -1,20 +1,19 @@ #include "glad.h" #include #include -#include -#include -#include "shader.h" #include #include +#include "shader.h" +#include "assetManager.h" + using namespace std; using namespace glm; namespace vb01{ Shader::Shader(string shaderPath, bool geometry){ this->geometry = geometry; - this->path = shaderPath; initShaders(shaderPath + ".vert", shaderPath + ".frag", shaderPath + ".geo"); loadShaders(); @@ -22,7 +21,6 @@ namespace vb01{ Shader::Shader(string vertShader, string fragShader){ this->geometry = false; - this->path = vertShader; initShaders(vertShader, fragShader, ""); loadShaders(); @@ -30,88 +28,30 @@ namespace vb01{ Shader::Shader(string vertShader, string fragShader, string geoShader){ this->geometry = true; - this->path = vertShader; initShaders(vertShader, fragShader, geoShader); loadShaders(); } - Shader::~Shader(){} - string Shader::getName(){ - int dirId = path.find_last_of('/'); - string name = (dirId != -1 ? path.substr(dirId + 1) : path); + int dirId = vString->path.find_last_of('/'); + string name = (dirId != -1 ? vString->path.substr(dirId + 1) : vString->path); - int dotId = path.find_last_of('.'); + int dotId = name.find_last_of('.'); - if(dotId != -1) - name = name.substr(0, dotId); + if(dotId != -1) + name = name.substr(0, dotId); - return name; + return name; } void Shader::initShaders(string vertShaderPath, string fragShaderPath, string geoShaderPath){ - ifstream vertShaderFile, fragShaderFile; - vertShaderFile.open(vertShaderPath); - fragShaderFile.open(fragShaderPath); - - stringstream vertShaderStream, fragShaderStream; - vertShaderStream << vertShaderFile.rdbuf(); - fragShaderStream << fragShaderFile.rdbuf(); - - vertShaderFile.close(); - fragShaderFile.close(); - - vString = vertShaderStream.str(); - fString = fragShaderStream.str(); + AssetManager *am = AssetManager::getSingleton(); + vString = (ShaderAsset*)am->getAsset(vertShaderPath); + fString = (ShaderAsset*)am->getAsset(fragShaderPath); - if(geometry){ - ifstream geoShaderFile; - geoShaderFile.open(geoShaderPath); - - stringstream geoShaderStream; - geoShaderStream << geoShaderFile.rdbuf(); - - geoShaderFile.close(); - gString = geoShaderStream.str(); - } - } - - void Shader::editShader(ShaderType type, int line, string insertion){ - replaceLine(type, line, insertion); - loadShaders(); - } - - void Shader::replaceLine(ShaderType type, int line, string insertion){ - string *shaderString; - - switch(type){ - case VERTEX_SHADER: - shaderString = &vString; - break; - case FRAGMENT_SHADER: - shaderString = &fString; - break; - case GEOMETRY_SHADER: - shaderString = &gString; - break; - } - - int numPassedLines = 0, lineStart = -1, lineEnd = -1; - for(int i = 0; i < shaderString->length(); i++) - if(shaderString[0][i] == '\n'){ - if(numPassedLines == line - 1) - lineStart = i + 1; - - if(numPassedLines == line){ - lineEnd = i; - break; - } - - numPassedLines++; - } - - *shaderString = shaderString->substr(0, lineStart) + insertion + shaderString->substr(lineEnd); + if(geometry) + gString = (ShaderAsset*)am->getAsset(geoShaderPath); } void Shader::pushShader(u32 &type, string &sString, int glType, ErrorType errorType){ @@ -124,11 +64,11 @@ namespace vb01{ void Shader::loadShaders(){ u32 vert, geo, frag; - pushShader(vert, vString, GL_VERTEX_SHADER, VERTEX_ERROR); - pushShader(frag, fString, GL_FRAGMENT_SHADER, FRAGMENT_ERROR); + pushShader(vert, vString->shaderString, GL_VERTEX_SHADER, VERTEX_ERROR); + pushShader(frag, fString->shaderString, GL_FRAGMENT_SHADER, FRAGMENT_ERROR); if(geometry) - pushShader(geo, gString, GL_GEOMETRY_SHADER, GEOMETRY_ERROR); + pushShader(geo, gString->shaderString, GL_GEOMETRY_SHADER, GEOMETRY_ERROR); id = glCreateProgram(); glAttachShader(id, vert); diff --git a/shader.h b/shader.h index 7092516..15ea0a0 100755 --- a/shader.h +++ b/shader.h @@ -4,6 +4,7 @@ #include #include +#include "shaderAsset.h" #include "vector.h" #include "util.h" @@ -17,10 +18,10 @@ namespace vb01{ Shader(std::string, bool = false); Shader(std::string, std::string); Shader(std::string, std::string, std::string); - ~Shader(); + ~Shader(){} std::string getName(); - void setNumLights(int); void use(); + void loadShaders(); void setMat4(glm::mat4, std::string); void setVec4(Vector4, std::string); void setVec3(Vector3, std::string); @@ -29,17 +30,16 @@ namespace vb01{ void setBool(bool, std::string); void setInt(int, std::string); void setUnsignedInt(u32, std::string); - void editShader(ShaderType, int, std::string); + void editShader(ShaderType, int, std::string){} inline bool isGeometry(){return geometry;} private: void initShaders(std::string, std::string, std::string); void replaceLine(ShaderType, int, std::string); - void loadShaders(); void pushShader(u32&, std::string&, int, ErrorType); void checkCompileErrors(u32, ErrorType); u32 id; bool geometry = false; - std::string path, vString, fString, gString; + ShaderAsset *vString = nullptr, *fString = nullptr, *gString = nullptr; friend class ShaderTest; }; diff --git a/shaderAsset.h b/shaderAsset.h new file mode 100644 index 0000000..75fa384 --- /dev/null +++ b/shaderAsset.h @@ -0,0 +1,17 @@ +#ifndef SHADER_ASSET_H +#define SHADER_ASSET_H + +#include "asset.h" + +namespace vb01{ + struct ShaderAsset : public Asset{ + std::string shaderString = ""; + + ShaderAsset(std::string p, std::string str){ + path = p; + shaderString = str; + } + }; +} + +#endif diff --git a/shaderReader.cpp b/shaderReader.cpp new file mode 100644 index 0000000..48a6682 --- /dev/null +++ b/shaderReader.cpp @@ -0,0 +1,30 @@ +#include "shaderReader.h" +#include "shaderAsset.h" + +#include +#include + +namespace vb01{ + using namespace std; + + static ShaderReader *shaderReader = nullptr; + + ShaderReader* ShaderReader::getSingleton(){ + if(!shaderReader) + shaderReader = new ShaderReader(); + + return shaderReader; + } + + Asset* ShaderReader::readAsset(string path){ + ifstream shaderFile; + shaderFile.open(path); + + stringstream shaderStream; + shaderStream << shaderFile.rdbuf(); + + shaderFile.close(); + + return new ShaderAsset(path, shaderStream.str()); + } +} diff --git a/shaderReader.h b/shaderReader.h new file mode 100644 index 0000000..379b0a4 --- /dev/null +++ b/shaderReader.h @@ -0,0 +1,16 @@ +#ifndef SHADER_READER_H +#define SHADER_READER_H + +#include "abstractAssetReader.h" + +namespace vb01{ + class ShaderReader : public AbstractAssetReader{ + public: + static ShaderReader* getSingleton(); + Asset* readAsset(std::string); + private: + ShaderReader(){} + }; +} + +#endif diff --git a/texture.cpp b/texture.cpp index c97fdec..dd7c064 100755 --- a/texture.cpp +++ b/texture.cpp @@ -60,6 +60,16 @@ namespace vb01{ } } + void Texture::loadImageData(ImageAsset *asset, int i){ + width = asset->width; + height = asset->height; + + glGenTextures(1, &texture[i]); + glBindTexture(GL_TEXTURE_2D, texture[i]); + glTexImage2D(GL_TEXTURE_2D, 0, png ? GL_RGBA : GL_RGB, width, height, 0, png ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, asset->image); + glGenerateMipmap(GL_TEXTURE_2D); + } + void Texture::create2DTexture(bool flip){ mixRatio = .1; @@ -69,19 +79,12 @@ namespace vb01{ if(paths[i].substr(length - 4, string::npos) == ".png") png = true; - glGenTextures(1, &texture[i]); - glBindTexture(GL_TEXTURE_2D, texture[i]); + loadImageData((ImageAsset*)AssetManager::getSingleton()->getAsset(paths[i])); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - ImageAsset *asset = (ImageAsset*)AssetManager::getSingleton()->getAsset(paths[i]); - width = asset->width; - height = asset->height; - - glTexImage2D(GL_TEXTURE_2D, 0, png ? GL_RGBA : GL_RGB, width, height, 0, png ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, asset->image); - glGenerateMipmap(GL_TEXTURE_2D); } } diff --git a/texture.frag b/texture.frag index e0b6333..75de987 100755 --- a/texture.frag +++ b/texture.frag @@ -15,10 +15,11 @@ layout (location = 1) out vec4 BrightColor; //0-POINT,1-DIRECTIONAL,2-SPOT struct Light{ - int type; + bool useAngle, additive, render; + int type, attenuation; vec3 pos, color, direction; float innerAngle, outerAngle; - float a, b, c, near, far; + float a, b, c, near, far, radius; sampler2D depthMap; samplerCube depthMapCube; mat4 lightMat; @@ -33,7 +34,7 @@ struct Texture{ uniform Texture textures[4]; uniform samplerCube environmentMap; uniform Light lights[numLights]; -uniform bool lightingEnabled, texturingEnabled, normalMapEnabled, specularMapEnabled, castShadow, environmentMapEnabled; +uniform bool lightingEnabled, constLightingEnabled, texturingEnabled, normalMapEnabled, specularMapEnabled, castShadow, environmentMapEnabled; uniform vec4 diffuseColor, specularColor; uniform float shinyness, specularStrength; uniform vec3 camPos; @@ -96,17 +97,38 @@ void main(){ vec3 diffuseCol = vec3(0), specularCol = vec3(0); if(checkLights){ + bool addedLighting = false; + for(int i = 0; i < numLights; i++){ + if(!lights[i].render) continue; + vec3 lightDir = vec3(0), viewDir = normalize(camPos - fragPos); - float attenuation = 1.0; - float a = lights[i].a, b = lights[i].b, c = lights[i].c, dist = length(fragPos - lights[i].pos), factor, coef = 1; + float attenuation = 1, coef = 1; + float factor = 0; + bool canAdd = false; if(lights[i].type == 0){ lightDir = normalize(lights[i].pos - fragPos); - attenuation = 1.0 / (a * dist * dist + b * dist + c); + float dist = length(lights[i].pos - fragPos), radius = lights[i].radius; + + if(lights[i].attenuation == 0){ + float a = lights[i].a, b = lights[i].b, c = lights[i].c; + attenuation = 1.0 / (a * dist * dist + b * dist + c); + factor = (lights[i].useAngle ? max(dot(lightDir, normalize(normal)), 0.) : 1) * attenuation; + } + else if(lights[i].attenuation == 1 && dist < radius && radius > 0){ + canAdd = !lights[i].additive; + factor = 1.0 - dist / lights[i].radius; + } + else if(lights[i].attenuation == 2 && dist < radius && radius > 0){ + canAdd = !lights[i].additive; + factor = 1; + } } - else if(lights[i].type == 1) + else if(lights[i].type == 1){ lightDir = -normalize(lights[i].direction); + factor = max(dot(lightDir, normalize(normal)), 0.) * attenuation; + } else if(lights[i].type == 2){ lightDir = normalize(lights[i].pos - fragPos); float innerAngle = lights[i].innerAngle; @@ -118,10 +140,18 @@ void main(){ if(angle > lights[i].outerAngle) continue; - } - factor = max(dot(lightDir, normal), 0.); - diffuseCol += lights[i].color * (factor * attenuation * coef); + factor = max(dot(lightDir, normalize(normal)), 0.) * attenuation * coef; + } + else factor = 1; + + + if(lights[i].additive) + diffuseCol += lights[i].color * factor; + else if(!lights[i].additive && constLightingEnabled && !addedLighting && canAdd){ + addedLighting = true; + diffuseCol += lights[i].color * factor; + } if(specularMapEnabled){ float specularSample = texture(textures[2].pastTexture, texCoords).r; @@ -130,12 +160,12 @@ void main(){ specularCol += specularStrength * spec * specularSample * lights[i].color; } - float shadow = getShadow(i); - diffuseCol *= (1.0 - shadow); + if(castShadow) + diffuseCol *= (1.0 - getShadow(i)); } - - finalColor *= vec4(diffuseCol + specularCol, 1); } + + finalColor *= vec4(diffuseCol + specularCol, 1); } float brightness = dot(finalColor.rgb, vec3(0.2126, 0.7152, 0.0722)); diff --git a/texture.h b/texture.h index beb1cb0..55f073d 100755 --- a/texture.h +++ b/texture.h @@ -10,6 +10,8 @@ #include FT_FREETYPE_H namespace vb01{ + struct ImageAsset; + class Texture : public Animatable{ public: ~Texture(); @@ -20,6 +22,7 @@ namespace vb01{ void select(int = 0, int = 0); void update(int = 0); void animate(float, KeyframeChannel); + void loadImageData(ImageAsset*, int = 0); inline u32* getTexture(int i = 0){return &(texture[i]);} inline std::string* getPath(){return paths;} inline int getNumFrames(){return numFrames;} diff --git a/util.cpp b/util.cpp index 10fa66d..b60ab1e 100755 --- a/util.cpp +++ b/util.cpp @@ -90,4 +90,15 @@ namespace vb01{ return str; } + + int findNthOccurence(string &str, string occ, int occId, bool forward){ + int occurenceId = (forward ? str.find(occ) : str.rfind(occ)), iteration = 0; + + while(occurenceId != -1 && iteration != occId){ + occurenceId = (forward ? str.find(occ, occurenceId + 1) : str.rfind(occ, occurenceId - 1)); + iteration++; + } + + return occurenceId; + } } diff --git a/util.h b/util.h index 5e40d5d..05b70e3 100755 --- a/util.h +++ b/util.h @@ -23,6 +23,7 @@ namespace vb01{ void readFile(std::string, std::vector&, int = 0, int = -1); void getLineData(std::string, std::string[], int, int = 0); + int findNthOccurence(std::string&, std::string, int, bool = true); int getCharId(std::string, char, bool = false); std::wstring stringToWstring(std::string str); std::string wstringToString(std::wstring wstr); diff --git a/xmlModelReader.cpp b/xmlModelReader.cpp index 011c6ca..f268ab7 100644 --- a/xmlModelReader.cpp +++ b/xmlModelReader.cpp @@ -42,6 +42,8 @@ namespace vb01{ assetRootNode->getDescendants(descendants); setupDrivers(descendants); + delete doc; + return asset; } @@ -57,41 +59,61 @@ namespace vb01{ } } + //TODO remove the 4 literal for bone weights and indices Mesh* XmlModelReader::processMesh(XMLElement *meshEl){ - vector vertPos, vertNorm; - vector weights; + int numVertPos = atoi(meshEl->Attribute("num_vertex_pos")); + int numVertexGroups = atoi(meshEl->Attribute("num_vertex_groups")); + const char *tagName = "vertdata"; - for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0; vertEl = vertEl->NextSiblingElement()){ + Vector3 *vertPos = new Vector3[numVertPos]; + float **weights = new float*[numVertPos]; + int **boneIndices = new int*[numVertPos], i = 0; + + for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0, i < numVertPos; vertEl = vertEl->NextSiblingElement(), i++){ float posX = atof(vertEl->Attribute("px")); float posY = atof(vertEl->Attribute("py")); float posZ = atof(vertEl->Attribute("pz")); - vertPos.push_back(Vector3(posX, posY, posZ)); + vertPos[i] = Vector3(posX, posY, posZ); - float normX = atof(vertEl->Attribute("nx")); - float normY = atof(vertEl->Attribute("ny")); - float normZ = atof(vertEl->Attribute("nz")); - vertNorm.push_back(Vector3(normX, normY, normZ)); + weights[i] = new float[4]; + boneIndices[i] = new int[4]; - for(XMLElement *weightEl = vertEl->FirstChildElement("weight"); weightEl; weightEl = weightEl->NextSiblingElement()) - weights.push_back(atof(weightEl->Attribute("value"))); + for(int j = 0; j < 4; j++){ + weights[i][j] = 0; + boneIndices[i][j] = -1; + } + + int boneIndex = 0, j = 0; + + for(XMLElement *weightEl = vertEl->FirstChildElement("weight"); weightEl, j < numVertexGroups; weightEl = weightEl->NextSiblingElement(), j++){ + float w = atof(weightEl->Attribute("value")); + + if(w > 0){ + weights[i][boneIndex] = w; + boneIndices[i][boneIndex] = j; + boneIndex++; + } + } } - int numVertexGroups = atoi(meshEl->Attribute("num_vertex_groups")); string *vertexGroups = new string[numVertexGroups]; tagName = "vertexgroup"; - int i = 0; + i = 0; - for(XMLElement *vertGroupEl = meshEl->FirstChildElement(tagName); vertGroupEl && strcmp(vertGroupEl->Name(), tagName) == 0; vertGroupEl = vertGroupEl->NextSiblingElement(), i++) - vertexGroups[i] = (vertGroupEl->Attribute("name")); + if(numVertexGroups > 0) + for(XMLElement *vertGroupEl = meshEl->FirstChildElement(tagName); vertGroupEl && strcmp(vertGroupEl->Name(), tagName) == 0 && i < numVertexGroups; vertGroupEl = vertGroupEl->NextSiblingElement(), i++) + vertexGroups[i] = vertGroupEl->Attribute("name"); i = 0; int numVertices = 3 * atoi(meshEl->Attribute("num_faces")); MeshData::Vertex *vertices = new MeshData::Vertex[numVertices]; tagName = "vert"; - vector vertIds; u32 *indices = new u32[numVertices]; + Vector3 *normals = new Vector3[numVertices]; + vector vertIds; + for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0; vertEl = vertEl->NextSiblingElement(), i++){ int id = atoi(vertEl->Attribute("id")); vertIds.push_back(id); @@ -110,60 +132,65 @@ namespace vb01{ float biTanZ = atof(vertEl->Attribute("bz")); Vector3 biTan = Vector3(biTanX, biTanY, biTanZ); + normals[i] = biTan.cross(tan); + MeshData::Vertex vertex; - vertex.pos = vertPos[id]; - vertex.norm = vertNorm[id]; + vertex.pos = &vertPos[id]; + vertex.norm = &normals[id]; vertex.uv = uv; vertex.tan = tan; vertex.biTan = biTan; - for(int j = 0, boneIndex = 0; j < numVertexGroups; j++){ - if(weights[id * numVertexGroups + j] > 0){ - vertex.boneIndices[boneIndex] = j; - vertex.weights[boneIndex] = weights[id * numVertexGroups + j]; - boneIndex++; - } - } + vertex.weights = weights[id]; + vertex.boneIndices = boneIndices[id]; indices[i] = i; vertices[i] = vertex; } - vertNorm.clear(); tagName = "shapekey"; i = 0; int numShapeKeys = atoi(meshEl->Attribute("num_shape_keys")); - MeshData::ShapeKey *shapeKeys = new MeshData::ShapeKey[numShapeKeys]; + MeshData::ShapeKey *shapeKeys = nullptr; + Vector3 **shapeKeyOffsets = nullptr; - for(XMLElement *shapeKeyEl = meshEl->FirstChildElement(tagName); shapeKeyEl && strcmp(shapeKeyEl->Name(), tagName) == 0; shapeKeyEl = shapeKeyEl->NextSiblingElement(), i++){ - string name = shapeKeyEl->Attribute("name"); - float minValue = atof(shapeKeyEl->Attribute("min")); - float maxValue = atof(shapeKeyEl->Attribute("max")); - shapeKeys[i] = MeshData::ShapeKey(name, minValue, minValue, maxValue); + if(numShapeKeys > 0){ + shapeKeys = new MeshData::ShapeKey[numShapeKeys]; + shapeKeyOffsets = new Vector3*[numVertPos]; - XMLElement *driverEl = shapeKeyEl->FirstChildElement("driver"); - KeyframeChannel channel = processKeyframeChannells(driverEl)[0]; - const char *nodeName = driverEl->Attribute("obj"); - const char *boneName = driverEl->Attribute("bone"); - Driver::VariableType type = Driver::getDriverVariableType(driverEl->Attribute("type")); - driversByNodeNames.push_back(make_pair(string(nodeName) + (boneName ? "." + string(boneName) : ""), new Driver(&shapeKeys[i], channel, type))); + for(int i = 0; i < numVertPos; i++) + shapeKeyOffsets[i] = new Vector3[100]; - vector shapeKeyPos; + for(XMLElement *shapeKeyEl = meshEl->FirstChildElement(tagName); shapeKeyEl && strcmp(shapeKeyEl->Name(), tagName) == 0 && i < numShapeKeys; shapeKeyEl = shapeKeyEl->NextSiblingElement(), i++){ + string name = shapeKeyEl->Attribute("name"); + float minValue = atof(shapeKeyEl->Attribute("min")); + float maxValue = atof(shapeKeyEl->Attribute("max")); + shapeKeys[i] = MeshData::ShapeKey(name, minValue, minValue, maxValue); - for(XMLElement *vertEl = shapeKeyEl->FirstChildElement("vert"); vertEl; vertEl = vertEl->NextSiblingElement()){ - float posX = atof(vertEl->Attribute("px")); - float posY = atof(vertEl->Attribute("py")); - float posZ = atof(vertEl->Attribute("pz")); - shapeKeyPos.push_back(Vector3(posX, posY, posZ)); - } + XMLElement *driverEl = shapeKeyEl->FirstChildElement("driver"); + KeyframeChannel channel = processKeyframeChannells(driverEl)[0]; + const char *nodeName = driverEl->Attribute("obj"); + const char *boneName = driverEl->Attribute("bone"); + Driver::VariableType type = Driver::getDriverVariableType(driverEl->Attribute("type")); + driversByNodeNames.push_back(make_pair(string(nodeName) + (boneName ? "." + string(boneName) : ""), new Driver(&shapeKeys[i], channel, type))); - for(int j = 0; j < numVertices; j++) - vertices[j].shapeKeyOffsets[i] = shapeKeyPos[vertIds[j]] - vertPos[vertIds[j]]; + int j = 0; + + for(XMLElement *vertEl = shapeKeyEl->FirstChildElement("vert"); vertEl; vertEl = vertEl->NextSiblingElement(), j++){ + float posX = atof(vertEl->Attribute("px")); + float posY = atof(vertEl->Attribute("py")); + float posZ = atof(vertEl->Attribute("pz")); + shapeKeyOffsets[j][i] = Vector3(posX, posY, posZ) - vertPos[j]; + } + } + + for(int i = 0; i < numVertices; i++) + vertices[i].shapeKeyOffsets = shapeKeyOffsets[vertIds[i]]; } const char *fullSkeletonName = meshEl->Attribute("skeleton"); string name = string(meshEl->Parent()->ToElement()->Attribute("name")) + string(meshEl->Attribute("name")); - Mesh *mesh = new Mesh(MeshData(vertices, indices, numVertices / 3, name, vertexGroups, numVertexGroups, (fullSkeletonName ? fullSkeletonName : ""), shapeKeys, numShapeKeys)); + Mesh *mesh = new Mesh(MeshData(vertPos, weights, boneIndices, shapeKeyOffsets, numVertPos, normals, vertices, indices, numVertices / 3, name, vertexGroups, numVertexGroups, (fullSkeletonName ? fullSkeletonName : ""), shapeKeys, numShapeKeys)); return mesh; } @@ -291,7 +318,7 @@ namespace vb01{ XMLElement *meshTag = xmlEl->FirstChildElement("mesh"); if(meshTag) - node->attachMesh(processMesh(meshTag)); + node->attachMesh(processMesh(meshTag)); XMLElement *lightTag = xmlEl->FirstChildElement("light");