From 87859fa044fca5f47fe07b8ffd4bd2de910f5ddb Mon Sep 17 00:00:00 2001 From: Miguel Angel Astor Romero Date: Sun, 26 Jun 2016 02:20:29 -0400 Subject: [PATCH] OpenGL gui working. Added sketch of the pheromone map. Added shaders. --- GLSLProgram.cpp | 224 ++++++++++++ GLSLProgram.hpp | 42 +++ Makefile | 11 +- gui.cpp | 58 ++- gui.hpp | 34 +- ias_robot.cpp | 9 +- ias_robot.hpp | 6 +- ias_ss.cpp | 19 +- include/pnglite.h | 227 ++++++++++++ maps/cave_mask.png | Bin 897 -> 1166 bytes ogl.cpp | 107 ++++++ ogl.hpp | 37 ++ pheromone.cpp | 59 +++ pheromone.hpp | 26 ++ pnglite.c | 877 +++++++++++++++++++++++++++++++++++++++++++++ shaders/basic.frag | 9 + shaders/basic.vert | 6 + 17 files changed, 1723 insertions(+), 28 deletions(-) create mode 100644 GLSLProgram.cpp create mode 100644 GLSLProgram.hpp create mode 100644 include/pnglite.h create mode 100644 ogl.cpp create mode 100644 ogl.hpp create mode 100644 pheromone.cpp create mode 100644 pheromone.hpp create mode 100644 pnglite.c create mode 100644 shaders/basic.frag create mode 100644 shaders/basic.vert diff --git a/GLSLProgram.cpp b/GLSLProgram.cpp new file mode 100644 index 0000000..f417491 --- /dev/null +++ b/GLSLProgram.cpp @@ -0,0 +1,224 @@ +#include +#include +#include + +#include "GLSLProgram.hpp" + +using namespace std; + +CGLSLProgram::CGLSLProgram(void) +{ + m_vIdShader[VERTEX] = 0; + m_vIdShader[FRAGMENT] = 0; + m_vIdShader[GEOMETRY] = 0; + m_vIdShader[TESSELATION] = 0; + m_mapVarShader.clear(); + m_mapSubroutines.clear(); +} + +CGLSLProgram::~CGLSLProgram(void) +{ + m_mapVarShader.clear(); + m_mapSubroutines.clear(); + if(m_uIdProgram > 0) + { + glDeleteProgram(m_uIdProgram); + cout << "Program deleted! " << endl; + } +} + +bool CGLSLProgram::loadShaderFile(std::string strFilename, GLuint iHandle) +{ + std::ifstream shaderSource(strFilename.c_str()); + if (!shaderSource.is_open()) + { + std::cerr<< " File not found "<< strFilename.c_str()<< endl; + return false; + } + // now read in the data + string strSource = std::string((std::istreambuf_iterator(shaderSource)), std::istreambuf_iterator()); + shaderSource.close(); + strSource+="\0"; + //pass the code to OGL + const char* data=strSource.c_str(); + glShaderSource(iHandle, 1, &data, NULL); + return true; +} + +void CGLSLProgram::recompileShader(std::string strFileName, SHADERTYPE typeShader) +{ + glDetachShader(m_uIdProgram, m_vIdShader[typeShader]); + loadShader(strFileName, typeShader); + glAttachShader(m_uIdProgram, m_vIdShader[typeShader]); + //link the program + glLinkProgram(m_uIdProgram); + checkLinkingErrors(); + glDeleteShader(m_vIdShader[typeShader]); + std::cout << "de pinga" << std::endl; +} + +void CGLSLProgram::loadShader(std::string strFileName, SHADERTYPE typeShader) +{ + GLuint hShader = 0; + GLint status; + + //Create shader object + switch (typeShader) + { + case VERTEX : { hShader = glCreateShader(GL_VERTEX_SHADER); break; } + case FRAGMENT : { hShader = glCreateShader(GL_FRAGMENT_SHADER); break; } + case GEOMETRY : { hShader = glCreateShader(GL_GEOMETRY_SHADER); break; } + case TESSELATION : { hShader = 0; std::cerr<<"not implemented.... yet :-)" << std::endl; } + } + + if(loadShaderFile(strFileName, hShader)) + { + //now compile the shader + glCompileShader(hShader); + glGetShaderiv(hShader, GL_COMPILE_STATUS, &status); + if(status == GL_FALSE) + { + char infoLog[1024]; + glGetShaderInfoLog(hShader, 1024, NULL, infoLog); + cout << "The shader at " << strFileName.c_str() << " failed to compile with the following errors:" << endl + << infoLog << endl; + glDeleteShader(hShader); + } + else //here, everything is OK + { + cout << "The shader at " << strFileName.c_str() << " was compiled without errors." << endl; + m_vIdShader[typeShader] = hShader; + } + } + else + { + std::cerr<< "something wrong loading the shader located in " << strFileName.c_str() << "." << std::endl; + glDeleteShader(hShader); + } +} + +void CGLSLProgram::checkLinkingErrors() +{ + GLint infologLength = 0; + glGetProgramiv(m_uIdProgram, GL_INFO_LOG_LENGTH, &infologLength); + //std::cerr<<"Link Log Length "< 1) + { + char *infoLog = new char[infologLength]; + GLint charsWritten = 0; + + glGetProgramInfoLog(m_uIdProgram, infologLength, &charsWritten, infoLog); + + std::cerr< 0) + glAttachShader(m_uIdProgram, m_vIdShader[VERTEX]); + if(m_vIdShader[FRAGMENT] > 0) + glAttachShader(m_uIdProgram, m_vIdShader[FRAGMENT]); + if(m_vIdShader[GEOMETRY] > 0) + glAttachShader(m_uIdProgram, m_vIdShader[GEOMETRY]); + //delete the shaders + glDeleteShader(m_vIdShader[VERTEX]); + glDeleteShader(m_vIdShader[FRAGMENT]); + glDeleteShader(m_vIdShader[GEOMETRY]); + checkLinkingErrors(); +} + +void CGLSLProgram::create_link() +{ + m_uIdProgram = glCreateProgram(); + //attach the shaders + if(m_vIdShader[VERTEX] > 0) + glAttachShader(m_uIdProgram, m_vIdShader[VERTEX]); + if(m_vIdShader[FRAGMENT] > 0) + glAttachShader(m_uIdProgram, m_vIdShader[FRAGMENT]); + if(m_vIdShader[GEOMETRY] > 0) + glAttachShader(m_uIdProgram, m_vIdShader[GEOMETRY]); + //link the program + glLinkProgram(m_uIdProgram); + //check errors on linking + checkLinkingErrors(); + //delete the shaders + glDeleteShader(m_vIdShader[VERTEX]); + glDeleteShader(m_vIdShader[FRAGMENT]); + glDeleteShader(m_vIdShader[GEOMETRY]); +} + +void CGLSLProgram::link() +{ + //link the program + glLinkProgram(m_uIdProgram); + //check errors on linking + checkLinkingErrors(); +} + +void CGLSLProgram::enable() +{ + glUseProgram(m_uIdProgram); +} + +void CGLSLProgram::disable() +{ + glUseProgram(0); +} + +GLuint CGLSLProgram::getId() +{ + return m_uIdProgram; +} + +void CGLSLProgram::addAttribute(std::string strParName) +{ + m_mapVarShader[strParName] = glGetAttribLocation(m_uIdProgram, strParName.c_str()); +} + +GLint CGLSLProgram::getLocation(std::string strParName) +{ + std::map::iterator it = m_mapVarShader.find(strParName); + if(it == m_mapVarShader.end()) + return -1; + else + return m_mapVarShader[strParName]; +} + +void CGLSLProgram::addUniform(std::string strParName) +{ + m_mapVarShader[strParName] = glGetUniformLocation(m_uIdProgram, strParName.c_str()); +} + +void CGLSLProgram::addUniformSubroutine(std::string strParName, int iShaderType) +{ + //m_vRoutinesIds.front() + m_mapVarShader[strParName] = glGetSubroutineUniformLocation(m_uIdProgram, iShaderType, strParName.c_str()); +} + +void CGLSLProgram::addSubroutine(std::string strFunctionName, unsigned int iShaderType) +{ + //m_vRoutinesIds.push_back(glGetSubroutineIndex(m_uIdProgram, iShaderType, strFunctionName.c_str())); + m_mapSubroutines[strFunctionName] = glGetSubroutineUniformLocation(m_uIdProgram, iShaderType, strFunctionName.c_str()); +} + +//only for 1 subroutine at time +void CGLSLProgram::setSubroutine(std::string strUniformName, std::string strSubRoutine, int iShaderType) +{ + int index = getLocation(strUniformName); + if(index > -1) + { + GLuint routine_index = glGetSubroutineIndex(m_uIdProgram, iShaderType, strSubRoutine.c_str()); + glUniformSubroutinesuiv(iShaderType, 1, &routine_index); + } +} diff --git a/GLSLProgram.hpp b/GLSLProgram.hpp new file mode 100644 index 0000000..fc2afef --- /dev/null +++ b/GLSLProgram.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include +#include +#include + +/// For now, just 1 vertex's type can be attach to the program +/// In order add more than 1 vertex's type to the program, the shaders should be named (eg. "shader1", "shader2" & so on) +class CGLSLProgram +{ + public: + enum SHADERTYPE {VERTEX = 0, FRAGMENT, GEOMETRY, TESSELATION}; + + GLuint m_uIdProgram; //id of the program + GLuint m_vIdShader[4]; //ids of the loaded shaders; the 4th is empty always + CGLSLProgram(void); + ~CGLSLProgram(void); + + void loadShader(std::string strFileName, SHADERTYPE typeShader); + void create(); + void create_link(); + void link(); + void enable(); + void disable(); + void addAttribute(std::string strParName); + void addSubroutine(std::string strFunctionName, unsigned int iShaderType); + void addUniform(std::string strParName); + void addUniformSubroutine(std::string strParName, int iShaderType); + GLint getLocation(std::string strParName); + GLuint getId(); + void setSubroutine(std::string strUniformName, std::string strSubRoutine, int iShaderType); + std::map m_mapSubroutines; + void recompileShader(std::string strFileName, SHADERTYPE typeShader); + private: + std::map m_mapVarShader; + std::vector m_vRoutinesIds; + bool loadShaderFile(std::string strFilename, GLuint iHandle); + void checkLinkingErrors(); +}; + diff --git a/Makefile b/Makefile index c7eabff..9d31b18 100644 --- a/Makefile +++ b/Makefile @@ -21,12 +21,14 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +CC = gcc CXX = g++ TARGET = ias-ss -OBJECTS = ias_ss.o robot.o ias_robot.o gui.o +OBJECTS = ias_ss.o robot.o ias_robot.o gui.o ogl.o GLSLProgram.o pnglite.o pheromone.o DEPENDS = $(OBJECTS:.o=.d) -CXXFLAGS = -ansi -pedantic -Wall `pkg-config --cflags playerc++` -LDLIBS = `pkg-config --libs playerc++` -lboost_system -lpthread -lGLU -lGL -lfltk -lfltk_gl +CFLAGS = -ansi -pedantic -Wall -I./include +CXXFLAGS = -ansi -pedantic -Wall `pkg-config --cflags playerc++` -I./include +LDLIBS = `pkg-config --libs playerc++` -lboost_system -lpthread -lz -lGLEW -lGLU -lGL -lfltk -lfltk_gl all: CXXFLAGS += -O2 -D_NDEBUG all: $(TARGET) @@ -39,6 +41,9 @@ $(TARGET): $(OBJECTS) -include $(DEPENDS) +pnglite.o: pnglite.c + $(CC) -c -o $@ $< $(CFLAGS) + %.o: %.cpp $(CXX) -c $(CXXFLAGS) $*.cpp -o $*.o $(CXX) -MM $(CXXFLAGS) $*.cpp > $*.d diff --git a/gui.cpp b/gui.cpp index a6429e2..3ab72d2 100644 --- a/gui.cpp +++ b/gui.cpp @@ -1,37 +1,71 @@ +/************************************************************************************* + * Copyright (c) 2016, Miguel Angel Astor Romero * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, this * + * list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright notice, * + * this list of conditions and the following disclaimer in the documentation * + * and/or other materials provided with the distribution. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *************************************************************************************/ + #include #include "gui.hpp" +#include "ogl.hpp" + +static const int REFRESH_MS = 0.016; // for 60 fps. static void redraw_callback(void * arg) { - Fl_Gl_Window * window = static_cast(arg); + GlGui * window = static_cast(arg); window->redraw(); - Fl::repeat_timeout(0.016, redraw_callback, window); + if(!window->isFinished()) + Fl::repeat_timeout(REFRESH_MS, redraw_callback, window); } -GlGui::GlGui(Fl_Window * parent, int x, int y, int w, int h, const char * l) : Fl_Gl_Window(x, y, w, h, l) { +GlGui::GlGui(Fl_Window * parent, int x, int y, int w, int h, const char * l, PheromoneMap * phero_map) : Fl_Gl_Window(x, y, w, h, l) { this->parent = parent; + this->phero_map = phero_map; title += l; initialized = false; - Fl::add_timeout(0.016, redraw_callback, this); - resizable(this); + done = false; } void GlGui::draw() { if(!valid()) { if(!initialized) { - //opengl::initialize(); - - std::cout << "OpenGL Version: " << (char*)glGetString(GL_VERSION) << std::endl; - std::cout << "OpenGL Vendor: " << (char*)glGetString(GL_VENDOR) << std::endl; - + ogl::initialize(phero_map); + Fl::add_timeout(REFRESH_MS, redraw_callback, this); initialized = true; } - //opengl::reshape(w(), h()); + ogl::reshape(w(), h()); } - //opengl::display(); + ogl::display(); } int GlGui::handle(int event) { return Fl_Gl_Window::handle(event); } + +void GlGui::finish() { + done = true; +} + +bool GlGui::isFinished() { + return done; +} diff --git a/gui.hpp b/gui.hpp index 949af90..c1c9c09 100644 --- a/gui.hpp +++ b/gui.hpp @@ -1,18 +1,44 @@ -#pragma once +/************************************************************************************* + * Copyright (c) 2016, Miguel Angel Astor Romero * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, this * + * list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright notice, * + * this list of conditions and the following disclaimer in the documentation * + * and/or other materials provided with the distribution. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *************************************************************************************/ #ifndef GUI_HPP #define GUI_HPP +#include #include #include #include #include -#include +#include "pheromone.hpp" class GlGui : public Fl_Gl_Window { public: - GlGui(Fl_Window * parent, int x, int y, int w, int h, const char * l); + GlGui(Fl_Window * parent, int x, int y, int w, int h, const char * l, PheromoneMap * phero_map); + void finish(); + bool isFinished(); protected: virtual void draw(); @@ -22,6 +48,8 @@ private: Fl_Window * parent; std::string title; bool initialized; + bool done; + PheromoneMap * phero_map; }; #endif diff --git a/ias_robot.cpp b/ias_robot.cpp index 7c5d6fd..9fa5cf1 100644 --- a/ias_robot.cpp +++ b/ias_robot.cpp @@ -34,12 +34,13 @@ static const long HALF_SECOND_USEC = 500000; static const double MIN_DIST_M = 1.5; static const double CRIT_DIST_M = 1.0; -IASSS_Robot::IASSS_Robot(std::string hostname, uint32_t port) : Robot(hostname, port) { - std::cout << "Creating IAS-SS robot on host \"" << hostname << "\" and port " << port << "." << std::endl; +IASSS_Robot::IASSS_Robot(std::string hostname, uint32_t port, PheromoneMap * phero_map) : Robot(hostname, port) { + _phero_map = phero_map; + log("Creating IAS-SS robot"); } IASSS_Robot::~IASSS_Robot() { - std::cout << "Destroying IAS-SS robot on " << _host_name << ":" << _port << std::endl; + log("Destroying IAS-SS robot"); } void IASSS_Robot::run() { @@ -70,7 +71,7 @@ void IASSS_Robot::run() { rv = gettimeofday(&tv, NULL); now = tv.tv_usec; delta = now - then; - + // Sleep for a bit before finishing this control iteration. wait = rv == 0 ? HALF_SECOND_USEC - delta : HALF_SECOND_USEC; usleep(wait); diff --git a/ias_robot.hpp b/ias_robot.hpp index a755846..596e28a 100644 --- a/ias_robot.hpp +++ b/ias_robot.hpp @@ -27,6 +27,7 @@ #define IAS_ROBOT_HPP #include "robot.hpp" +#include "pheromone.hpp" /** * Concrete robot that implements the IAS-SS architecture as defined in: @@ -41,12 +42,13 @@ */ class IASSS_Robot : Robot { public: - IASSS_Robot(std::string hostname, uint32_t port); + IASSS_Robot(std::string hostname, uint32_t port, PheromoneMap * phero_map); virtual ~IASSS_Robot(); - virtual void run(); private: + PheromoneMap * _phero_map; + void avoid_wall(float front_speed, float turn_speed); }; diff --git a/ias_ss.cpp b/ias_ss.cpp index a86fbd0..f245096 100644 --- a/ias_ss.cpp +++ b/ias_ss.cpp @@ -37,11 +37,18 @@ const int H = 256; const uint32_t PORT = PlayerCc::PLAYER_PORTNUM + 1; const uint32_t NUM_ROBOTS = 4; -static bool done = false; -static Fl_Window * window; +static bool done = false; +static Fl_Window * window = NULL; +static GlGui * glWindow = NULL; +static PheromoneMap * phero_map = NULL; extern "C" void handler(int signal) { done = true; + + if(window != NULL) { + glWindow->finish(); + window->hide(); + } } extern "C" void * robot_thread(void * arg) { @@ -57,7 +64,7 @@ extern "C" void * robot_thread(void * arg) { void create_gui(int argc, char **argv) { window = new Fl_Window(20, 40, W, H, TITLE); - new GlGui(window, 0, 0, W, H, TITLE); + glWindow = new GlGui(window, 0, 0, W, H, TITLE, phero_map); window->end(); window->show(argc, argv); window->make_current(); @@ -70,9 +77,11 @@ int main(int argc, char **argv) { signal(SIGINT, handler); try { + phero_map = new PheromoneMap("maps/cave_mask.png"); + // Initialize the robot objects and threads. for(uint32_t i = 0; i < NUM_ROBOTS; ++i) { - robots.push_back(new IASSS_Robot(PlayerCc::PLAYER_HOSTNAME, PORT + i)); + robots.push_back(new IASSS_Robot(PlayerCc::PLAYER_HOSTNAME, PORT + i, phero_map)); if(pthread_create(&robot_threads[i], NULL, robot_thread, static_cast(robots[i])) != 0) { perror("Could not create robot thread"); @@ -93,6 +102,8 @@ int main(int argc, char **argv) { } robots.clear(); + delete phero_map; + } catch (PlayerCc::PlayerError & e) { std::cerr << e << std::endl; return EXIT_FAILURE; diff --git a/include/pnglite.h b/include/pnglite.h new file mode 100644 index 0000000..f464c46 --- /dev/null +++ b/include/pnglite.h @@ -0,0 +1,227 @@ +/* pnglite.h - Interface for pnglite library + Copyright (c) 2007 Daniel Karling + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + Daniel Karling + daniel.karling@gmail.com + */ + + +#ifndef _PNGLITE_H_ +#define _PNGLITE_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +/* + Enumerations for pnglite. + Negative numbers are error codes and 0 and up are okay responses. +*/ + +enum +{ + PNG_DONE = 1, + PNG_NO_ERROR = 0, + PNG_FILE_ERROR = -1, + PNG_HEADER_ERROR = -2, + PNG_IO_ERROR = -3, + PNG_EOF_ERROR = -4, + PNG_CRC_ERROR = -5, + PNG_MEMORY_ERROR = -6, + PNG_ZLIB_ERROR = -7, + PNG_UNKNOWN_FILTER = -8, + PNG_NOT_SUPPORTED = -9, + PNG_WRONG_ARGUMENTS = -10 +}; + +/* + The five different kinds of color storage in PNG files. +*/ + +enum +{ + PNG_GREYSCALE = 0, + PNG_TRUECOLOR = 2, + PNG_INDEXED = 3, + PNG_GREYSCALE_ALPHA = 4, + PNG_TRUECOLOR_ALPHA = 6 +}; + +/* + Typedefs for callbacks. +*/ + +typedef unsigned (*png_write_callback_t)(void* input, size_t size, size_t numel, void* user_pointer); +typedef unsigned (*png_read_callback_t)(void* output, size_t size, size_t numel, void* user_pointer); +typedef void (*png_free_t)(void* p); +typedef void * (*png_alloc_t)(size_t s); + +typedef struct +{ + void* zs; /* pointer to z_stream */ + png_read_callback_t read_fun; + png_write_callback_t write_fun; + void* user_pointer; + + unsigned char* png_data; + unsigned png_datalen; + + unsigned width; + unsigned height; + unsigned char depth; + unsigned char color_type; + unsigned char compression_method; + unsigned char filter_method; + unsigned char interlace_method; + unsigned char bpp; +}png_t; + +/* + Function: png_init + + This function initializes pnglite. The parameters can be used to set your own memory allocation routines following these formats: + + > void* (*custom_alloc)(size_t s) + > void (*custom_free)(void* p) + Parameters: + pngalloc - Pointer to custom allocation routine. If 0 is passed, malloc from libc will be used. + pngfree - Pointer to custom free routine. If 0 is passed, free from libc will be used. + + Returns: + Always returns PNG_NO_ERROR. +*/ + +int png_init(png_alloc_t pngalloc, png_free_t pngfree); + +/* + Function: png_open_file + + This function is used to open a png file with the internal file IO system. This function should be used instead of + png_open if no custom read function is used. + + Parameters: + png - Empty png_t struct. + filename - Filename of the file to be opened. + + Returns: + PNG_NO_ERROR on success, otherwise an error code. +*/ + +int png_open_file(png_t *png, const char* filename); + +int png_open_file_read(png_t *png, const char* filename); +int png_open_file_write(png_t *png, const char* filename); + +/* + Function: png_open + + This function reads or writes a png from/to the specified callback. The callbacks should be of the format: + + > size_t (*png_write_callback_t)(void* input, size_t size, size_t numel, void* user_pointer); + > size_t (*png_read_callback_t)(void* output, size_t size, size_t numel, void* user_pointer). + + Only one callback has to be specified. The read callback in case of PNG reading, otherwise the write callback. + + Writing: + The callback will be called like fwrite. + + Reading: + The callback will be called each time pnglite needs more data. The callback should read as much data as requested, + or return 0. This should always be possible if the PNG is sane. If the output-buffer is a null-pointer the callback + should only skip ahead the specified number of elements. If the callback is a null-pointer the user_pointer will be + treated as a file pointer (use png_open_file instead). + + Parameters: + png - png_t struct + read_fun - Callback function for reading. + user_pointer - User pointer to be passed to read_fun. + + Returns: + PNG_NO_ERROR on success, otherwise an error code. +*/ + +int png_open(png_t* png, png_read_callback_t read_fun, void* user_pointer); + +int png_open_read(png_t* png, png_read_callback_t read_fun, void* user_pointer); +int png_open_write(png_t* png, png_write_callback_t write_fun, void* user_pointer); + +/* + Function: png_print_info + + This function prints some info about the opened png file to stdout. + + Parameters: + png - png struct to get info from. +*/ + +void png_print_info(png_t* png); + +/* + Function: png_error_string + + This function translates an error code to a human readable string. + + Parameters: + error - Error code. + + Returns: + Pointer to string. +*/ + +char* png_error_string(int error); + +/* + Function: png_get_data + + This function decodes the opened png file and stores the result in data. data should be big enough to hold the decoded png. Required size will be: + + > width*height*(bytes per pixel) + + Parameters: + data - Where to store result. + + Returns: + PNG_NO_ERROR on success, otherwise an error code. +*/ + +int png_get_data(png_t* png, unsigned char* data); + +int png_set_data(png_t* png, unsigned width, unsigned height, char depth, int color, unsigned char* data); + +/* + Function: png_close_file + + Closes an open png file pointer. Should only be used when the png has been opened with png_open_file. + + Parameters: + png - png to close. + + Returns: + PNG_NO_ERROR +*/ + +int png_close_file(png_t* png); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/maps/cave_mask.png b/maps/cave_mask.png index 7d104b314d91a77e6d4d10cf8b49e30e509e1b8f..32518d26e9d3f291a10afc091163e79a157e052b 100644 GIT binary patch literal 1166 zcmah|4N#MH7=PZ^ZH&#~NKnUczLi#d2;<-&q;$*iF{D9OI5KStlM?ypK)!CWx5Z@; z<*rT}0kK2U>>x&gkbt~cf)y}fd{{JE79={{JQm3Ytas3z*VSGBk9$7;|NB3`|L=L8 zvLs0?i{Zln0G2pTv=;y&RRriLDGcmgA*7%k-V-YVr)z4v&VN99+;iemasikRxi&Iv zELkL-Zh7Koquoq2A1e2;jit&z04Q9sNcckGkF&;!z1%3aV90aI>6A~stD>l$zBSx< z@XmtQg-{z$Jb$AlhGlUa_QQYa zi(;v#*YansvYIN@7^KD=@d|@-N}(Rw@OFrywgo}>$Lv2lzZ7xkcuH&i zH367k38N6rXMGiZYzWBu?NBHi?pzE(Nb!lj50&Zt!sBSdHP$1#QG!7b|u)zGkg ztGleX{-b5D0y&aUxzC{Qu2b@~t@)PZw4aKON?t}EF)Qr;Wym+#XXT40`W=neu#w{j*X;G@I$~NTJ7_x(I6K=~GL#5>RT|kPnz$3Dlfq`2Hgc&d0t@{HM zWH0gbb!C6RCMjyfE@<)R9s>ijf~SjPNX4zUckdRhHsEm!wBvvO|J1A4WtY_$n>T*l zTw0mtm#mv|Q-JAK-{EbS7wSf3r2G;WyV^{5Y{|i|eCfJyiv8||Ll?Vpe&cM*H zi(wJdrn!9T_L6cjjEmTxFb9+}Omhrm+&cZ>yr}`6jOVyCvRUVdT$m>QV1mQS>I1@w zd2UMlJJ-8RSpFxR$K%|m`F3jk48iVCi`6r(GOBSEm~l9C_KJ%N`-Dku;#|`ur*ptf99=UCd3dQ6=Kn7X7;~gzhq|fXZ;OaD!)|~e}gnEDB}MT#rSz! z@b5oo&Un7cX1Fug;37-1yuB90xP}Djg@uXC)1Lj~ny~v%{@evye;ofm&*Aih|J!DY zu4%BB3zK>9$|j@p(%ujj-K!7xIb4`Dwc6Zq-`oUs$J3zG|BwU*S3{B_q;6DT$F8sm=%<)IDX|E@Cbu!ngZL36e3UVb_llmZ-H zshtRY_(}A^+u0M>?r_+*{} zb1%$e+%UDS>}zqZM8jHL#ofObmLJc5tv<2$hX*&$2dP%Egk6<^D|-L!5nO+l_iu&a zI!-2p)o@k_cl&wKeKilwY#M6+l&3On*xvsA0cYcRPM`f+IsJW?>xH+R{C{4$VgGfL zjr>qu4XM(GS_}<87&b0HUT5d+eN*n+Kjqw+pY|6yx_p6~oRGG{qM<9i!Rg=2?TPn} zJ^yU! +#include +#include +#include +#include +#include + +#include "ogl.hpp" +#include "GLSLProgram.hpp" + +#define BUFFER_OFFSET(i) ((char *)NULL + (i)) + +namespace ogl +{ + // Variables + static CGLSLProgram m_program; + static PheromoneMap * m_phero_map = NULL; + static GLuint m_textureHandle; + + // Quad definition + static glm::vec4 vec_points[6]; + static glm::vec2 vec_tex_coords[6]; + + static void quad() { + vec_tex_coords[0] = glm::vec2( 0.0f, 0.0f); vec_points[0] = glm::vec4( -0.5f, -0.5f, 0.0f, 1.0f ); + vec_tex_coords[1] = glm::vec2( 0.0f, 1.0f); vec_points[1] = glm::vec4( -0.5f, 0.5f, 0.0f, 1.0f ); + vec_tex_coords[2] = glm::vec2( 1.0f, 0.0f); vec_points[2] = glm::vec4( 0.5f, -0.5f, 0.0f, 1.0f ); + vec_tex_coords[3] = glm::vec2( 1.0f, 0.0f); vec_points[3] = glm::vec4( 0.5f, -0.5f, 0.0f, 1.0f ); + vec_tex_coords[4] = glm::vec2( 0.0f, 1.0f); vec_points[4] = glm::vec4( -0.5f, 0.5f, 0.0f, 1.0f ); + vec_tex_coords[5] = glm::vec2( 1.0f, 1.0f); vec_points[5] = glm::vec4( 0.5f, 0.5f, 0.0f, 1.0f ); + } + + void initialize(PheromoneMap * phero_map) { + glewInit(); + + quad(); + m_phero_map = phero_map; + + m_program.loadShader("shaders/basic.vert", CGLSLProgram::VERTEX); + m_program.loadShader("shaders/basic.frag", CGLSLProgram::FRAGMENT); + m_program.create_link(); + m_program.enable(); + m_program.addUniform("sTexture"); + m_program.disable(); + + std::cout << "OpenGL Version: " << (char*)glGetString(GL_VERSION) << std::endl; + std::cout << "OpenGL Vendor: " << (char*)glGetString(GL_VENDOR) << std::endl; + } + + void display() { + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(0.15f, 0.15f, 0.15f, 1.0f); + + if(m_phero_map != NULL) + m_textureHandle = m_phero_map->s_build_texture(); // Good grief! + + m_program.enable(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureHandle); + glUniform1i(m_program.getLocation("sTexture"), 0); + + glBegin(GL_TRIANGLES); { + for(int i = 0; i < 6; i++) { + glTexCoord2f(vec_tex_coords[i].s, vec_tex_coords[i].t); + glVertex4f(vec_points[i].x, vec_points[i].y, vec_points[i].z, vec_points[i].w); + } + } glEnd(); + + m_program.disable(); + } + + void reshape(int w, int h) { + if(h == 0) + h = 1; + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(-0.5, 0.5, -0.5, 0.5); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + } +} diff --git a/ogl.hpp b/ogl.hpp new file mode 100644 index 0000000..9d2356f --- /dev/null +++ b/ogl.hpp @@ -0,0 +1,37 @@ +/************************************************************************************* + * Copyright (c) 2016, Miguel Angel Astor Romero * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, this * + * list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright notice, * + * this list of conditions and the following disclaimer in the documentation * + * and/or other materials provided with the distribution. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *************************************************************************************/ + +#ifndef OGL_HPP +#define OGL_HPP + +#include "pheromone.hpp" + +namespace ogl { + void initialize(PheromoneMap * phero_map); + void display(); + void reshape(int w, int h); +} + +#endif diff --git a/pheromone.cpp b/pheromone.cpp new file mode 100644 index 0000000..d5f2f7d --- /dev/null +++ b/pheromone.cpp @@ -0,0 +1,59 @@ +#include +#include +#include + +#include "pheromone.hpp" + +PheromoneMap::PheromoneMap(const char * file_name) { + load_map(file_name); + sem_init(&map_semaphore, 0, 1); + tex_created = false; +} + +PheromoneMap::~PheromoneMap() { + free(data); + sem_destroy(&map_semaphore); + + if(tex_created) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, handle); + glDeleteTextures(1, &handle); + } +} + +void PheromoneMap::load_map(const char * file_name) { + png_t tex; + + png_init(0, 0); + png_open_file_read(&tex, file_name); + data = (unsigned char*) malloc(tex.width * tex.height * tex.bpp); + png_get_data(&tex, data); + + std::cout << "Loaded map \"" << file_name << "\" :: " << tex.width << "x" << tex.height << "x" << (int)tex.bpp << std::endl; + m_width = tex.width; + m_height = tex.height; + m_bpp = tex.bpp; + + png_close_file(&tex); +} + +GLuint PheromoneMap::s_build_texture() { + sem_wait(&map_semaphore); { + if(tex_created) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, handle); + glDeleteTextures(1, &handle); + } + + glGenTextures(1, &handle); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, handle); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_width, m_height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + tex_created = true; + } sem_post(&map_semaphore); + + return handle; +} diff --git a/pheromone.hpp b/pheromone.hpp new file mode 100644 index 0000000..2a1262b --- /dev/null +++ b/pheromone.hpp @@ -0,0 +1,26 @@ +#ifndef PHEROMONE_HPP +#define PHEROMONE_HPP + +#include +#include + +class PheromoneMap { +public: + PheromoneMap(const char * file_name); + ~PheromoneMap(); + + GLuint s_build_texture(); + +private: + unsigned char * data; + unsigned m_width; + unsigned m_height; + unsigned char m_bpp; + sem_t map_semaphore; + bool tex_created; + GLuint handle; + + void load_map(const char * file_name); +}; + +#endif diff --git a/pnglite.c b/pnglite.c new file mode 100644 index 0000000..f33bae0 --- /dev/null +++ b/pnglite.c @@ -0,0 +1,877 @@ +/* pnglite.c - pnglite library + For conditions of distribution and use, see copyright notice in pnglite.h +*/ +#define DO_CRC_CHECKS 1 +#define USE_ZLIB 1 + +#if USE_ZLIB +#include +#else +#include "zlite.h" +#endif + +#include +#include +#include +#include + + + +static png_alloc_t png_alloc; +static png_free_t png_free; + +static size_t file_read(png_t* png, void* out, size_t size, size_t numel) +{ + size_t result; + if(png->read_fun) + { + result = png->read_fun(out, size, numel, png->user_pointer); + } + else + { + if(!out) + { + result = fseek(png->user_pointer, (long)(size*numel), SEEK_CUR); + } + else + { + result = fread(out, size, numel, png->user_pointer); + } + } + + return result; +} + +static size_t file_write(png_t* png, void* p, size_t size, size_t numel) +{ + size_t result; + + if(png->write_fun) + { + result = png->write_fun(p, size, numel, png->user_pointer); + } + else + { + result = fwrite(p, size, numel, png->user_pointer); + } + + return result; +} + +static int file_read_ul(png_t* png, unsigned *out) +{ + unsigned char buf[4]; + + if(file_read(png, buf, 1, 4) != 4) + return PNG_FILE_ERROR; + + *out = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3]; + + return PNG_NO_ERROR; +} + +static int file_write_ul(png_t* png, unsigned in) +{ + unsigned char buf[4]; + + buf[0] = (in>>24) & 0xff; + buf[1] = (in>>16) & 0xff; + buf[2] = (in>>8) & 0xff; + buf[3] = (in) & 0xff; + + if(file_write(png, buf, 1, 4) != 4) + return PNG_FILE_ERROR; + + return PNG_NO_ERROR; +} + + +static unsigned get_ul(unsigned char* buf) +{ + unsigned result; + unsigned char foo[4]; + + memcpy(foo, buf, 4); + + result = (foo[0]<<24) | (foo[1]<<16) | (foo[2]<<8) | foo[3]; + + return result; +} + +static unsigned set_ul(unsigned char* buf, unsigned in) +{ + buf[0] = (in>>24) & 0xff; + buf[1] = (in>>16) & 0xff; + buf[2] = (in>>8) & 0xff; + buf[3] = (in) & 0xff; + + return PNG_NO_ERROR; +} + +int png_init(png_alloc_t pngalloc, png_free_t pngfree) +{ + if(pngalloc) + png_alloc = pngalloc; + else + png_alloc = &malloc; + + if(pngfree) + png_free = pngfree; + else + png_free = &free; + + return PNG_NO_ERROR; +} + +static int png_get_bpp(png_t* png) +{ + int bpp; + + switch(png->color_type) + { + case PNG_GREYSCALE: + bpp = 1; break; + case PNG_TRUECOLOR: + bpp = 3; break; + case PNG_INDEXED: + bpp = 1; break; + case PNG_GREYSCALE_ALPHA: + bpp = 2; break; + case PNG_TRUECOLOR_ALPHA: + bpp = 4; break; + default: + return PNG_FILE_ERROR; + } + + bpp *= png->depth/8; + + return bpp; +} + +static int png_read_ihdr(png_t* png) +{ + unsigned length; +#if DO_CRC_CHECKS + unsigned orig_crc; + unsigned calc_crc; +#endif + unsigned char ihdr[13+4]; /* length should be 13, make room for type (IHDR) */ + + file_read_ul(png, &length); + + if(length != 13) + { + printf("%d\n", length); + return PNG_CRC_ERROR; + } + + if(file_read(png, ihdr, 1, 13+4) != 13+4) + return PNG_EOF_ERROR; +#if DO_CRC_CHECKS + file_read_ul(png, &orig_crc); + + calc_crc = crc32(0L, 0, 0); + calc_crc = crc32(calc_crc, ihdr, 13+4); + + if(orig_crc != calc_crc) + return PNG_CRC_ERROR; +#else + file_read_ul(png); +#endif + + png->width = get_ul(ihdr+4); + png->height = get_ul(ihdr+8); + png->depth = ihdr[12]; + png->color_type = ihdr[13]; + png->compression_method = ihdr[14]; + png->filter_method = ihdr[15]; + png->interlace_method = ihdr[16]; + + if(png->color_type == PNG_INDEXED) + return PNG_NOT_SUPPORTED; + + if(png->depth != 8 && png->depth != 16) + return PNG_NOT_SUPPORTED; + + if(png->interlace_method) + return PNG_NOT_SUPPORTED; + + return PNG_NO_ERROR; +} + +static int png_write_ihdr(png_t* png) +{ + unsigned char ihdr[13+4]; + unsigned char *p = ihdr; + unsigned crc; + + file_write(png, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 1, 8); + + file_write_ul(png, 13); + + *p = 'I'; p++; + *p = 'H'; p++; + *p = 'D'; p++; + *p = 'R'; p++; + set_ul(p, png->width); p+=4; + set_ul(p, png->height); p+=4; + *p = png->depth; p++; + *p = png->color_type; p++; + *p = 0; p++; + *p = 0; p++; + *p = 0; p++; + + file_write(png, ihdr, 1, 13+4); + + crc = crc32(0L, 0, 0); + crc = crc32(crc, ihdr, 13+4); + + file_write_ul(png, crc); + + return PNG_NO_ERROR; +} + +void png_print_info(png_t* png) +{ + printf("PNG INFO:\n"); + printf("\twidth:\t\t%d\n", png->width); + printf("\theight:\t\t%d\n", png->height); + printf("\tdepth:\t\t%d\n", png->depth); + printf("\tcolor:\t\t"); + + switch(png->color_type) + { + case PNG_GREYSCALE: printf("greyscale\n"); break; + case PNG_TRUECOLOR: printf("truecolor\n"); break; + case PNG_INDEXED: printf("palette\n"); break; + case PNG_GREYSCALE_ALPHA: printf("greyscale with alpha\n"); break; + case PNG_TRUECOLOR_ALPHA: printf("truecolor with alpha\n"); break; + default: printf("unknown, this is not good\n"); break; + } + + printf("\tcompression:\t%s\n", png->compression_method?"unknown, this is not good":"inflate/deflate"); + printf("\tfilter:\t\t%s\n", png->filter_method?"unknown, this is not good":"adaptive"); + printf("\tinterlace:\t%s\n", png->interlace_method?"interlace":"no interlace"); +} + +int png_open_read(png_t* png, png_read_callback_t read_fun, void* user_pointer) +{ + char header[8]; + int result; + + png->read_fun = read_fun; + png->write_fun = 0; + png->user_pointer = user_pointer; + + if(!read_fun && !user_pointer) + return PNG_WRONG_ARGUMENTS; + + if(file_read(png, header, 1, 8) != 8) + return PNG_EOF_ERROR; + + if(memcmp(header, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8) != 0) + return PNG_HEADER_ERROR; + + result = png_read_ihdr(png); + + png->bpp = (unsigned char)png_get_bpp(png); + + return result; +} + +int png_open_write(png_t* png, png_write_callback_t write_fun, void* user_pointer) +{ + png->write_fun = write_fun; + png->read_fun = 0; + png->user_pointer = user_pointer; + + if(!write_fun && !user_pointer) + return PNG_WRONG_ARGUMENTS; + + return PNG_NO_ERROR; +} + +int png_open(png_t* png, png_read_callback_t read_fun, void* user_pointer) +{ + return png_open_read(png, read_fun, user_pointer); +} + +int png_open_file_read(png_t *png, const char* filename) +{ + FILE* fp = fopen(filename, "rb"); + + if(!fp) + return PNG_FILE_ERROR; + + return png_open_read(png, 0, fp); +} + +int png_open_file_write(png_t *png, const char* filename) +{ + FILE* fp = fopen(filename, "wb"); + + if(!fp) + return PNG_FILE_ERROR; + + return png_open_write(png, 0, fp); +} + +int png_open_file(png_t *png, const char* filename) +{ + return png_open_file_read(png, filename); +} + +int png_close_file(png_t* png) +{ + fclose(png->user_pointer); + + return PNG_NO_ERROR; +} + +static int png_init_deflate(png_t* png, unsigned char* data, int datalen) +{ + z_stream *stream; + png->zs = png_alloc(sizeof(z_stream)); + + stream = png->zs; + + if(!stream) + return PNG_MEMORY_ERROR; + + memset(stream, 0, sizeof(z_stream)); + + if(deflateInit(stream, Z_DEFAULT_COMPRESSION) != Z_OK) + return PNG_ZLIB_ERROR; + + stream->next_in = data; + stream->avail_in = datalen; + + return PNG_NO_ERROR; +} + +static int png_init_inflate(png_t* png) +{ +#if USE_ZLIB + z_stream *stream; + png->zs = png_alloc(sizeof(z_stream)); +#else + zl_stream *stream; + png->zs = png_alloc(sizeof(zl_stream)); +#endif + + stream = png->zs; + + if(!stream) + return PNG_MEMORY_ERROR; + + + +#if USE_ZLIB + memset(stream, 0, sizeof(z_stream)); + if(inflateInit(stream) != Z_OK) + return PNG_ZLIB_ERROR; +#else + memset(stream, 0, sizeof(zl_stream)); + if(z_inflateInit(stream) != Z_OK) + return PNG_ZLIB_ERROR; +#endif + + stream->next_out = png->png_data; + stream->avail_out = png->png_datalen; + + return PNG_NO_ERROR; +} + +static int png_end_deflate(png_t* png) +{ + z_stream *stream = png->zs; + + if(!stream) + return PNG_MEMORY_ERROR; + + deflateEnd(stream); + + png_free(png->zs); + + return PNG_NO_ERROR; +} + +static int png_end_inflate(png_t* png) +{ +#if USE_ZLIB + z_stream *stream = png->zs; +#else + zl_stream *stream = png->zs; +#endif + + if(!stream) + return PNG_MEMORY_ERROR; + +#if USE_ZLIB + if(inflateEnd(stream) != Z_OK) +#else + if(z_inflateEnd(stream) != Z_OK) +#endif + { + printf("ZLIB says: %s\n", stream->msg); + return PNG_ZLIB_ERROR; + } + + png_free(png->zs); + + return PNG_NO_ERROR; +} + +static int png_inflate(png_t* png, char* data, int len) +{ + int result; +#if USE_ZLIB + z_stream *stream = png->zs; +#else + zl_stream *stream = png->zs; +#endif + + if(!stream) + return PNG_MEMORY_ERROR; + + stream->next_in = (unsigned char*)data; + stream->avail_in = len; + +#if USE_ZLIB + result = inflate(stream, Z_SYNC_FLUSH); +#else + result = z_inflate(stream); +#endif + + if(result != Z_STREAM_END && result != Z_OK) + { + printf("%s\n", stream->msg); + return PNG_ZLIB_ERROR; + } + + if(stream->avail_in != 0) + return PNG_ZLIB_ERROR; + + return PNG_NO_ERROR; +} + +static int png_deflate(png_t* png, char* outdata, int outlen, int *outwritten) +{ + int result; + + z_stream *stream = png->zs; + + + if(!stream) + return PNG_MEMORY_ERROR; + + stream->next_out = (unsigned char*)outdata; + stream->avail_out = outlen; + + result = deflate(stream, Z_SYNC_FLUSH); + + *outwritten = outlen - stream->avail_out; + + if(result != Z_STREAM_END && result != Z_OK) + { + printf("%s\n", stream->msg); + return PNG_ZLIB_ERROR; + } + + return result; +} + +static int png_write_idats(png_t* png, unsigned char* data) +{ + unsigned char *chunk; + unsigned long written; + unsigned long crc; + unsigned size = png->width * png->height * png->bpp + png->height; + + (void)png_init_deflate; + (void)png_end_deflate; + (void)png_deflate; + + chunk = png_alloc(size); + memcpy(chunk, "IDAT", 4); + + written = size; + compress(chunk+4, &written, data, size); + + crc = crc32(0L, Z_NULL, 0); + crc = crc32(crc, chunk, written+4); + set_ul(chunk+written+4, crc); + file_write_ul(png, written); + file_write(png, chunk, 1, written+8); + png_free(chunk); + + file_write_ul(png, 0); + file_write(png, "IEND", 1, 4); + crc = crc32(0L, (const unsigned char *)"IEND", 4); + file_write_ul(png, crc); + + return PNG_NO_ERROR; +} + +static int png_read_idat(png_t* png, unsigned firstlen) +{ + unsigned type = 0; + char *chunk; + int result; + unsigned length = firstlen; + unsigned old_len = length; + +#if DO_CRC_CHECKS + unsigned orig_crc; + unsigned calc_crc; +#endif + + chunk = png_alloc(firstlen); + + result = png_init_inflate(png); + + if(result != PNG_NO_ERROR) + { + png_end_inflate(png); + png_free(chunk); + return result; + } + + do + { + if(file_read(png, chunk, 1, length) != length) + { + png_end_inflate(png); + png_free(chunk); + return PNG_FILE_ERROR; + } + +#if DO_CRC_CHECKS + calc_crc = crc32(0L, Z_NULL, 0); + calc_crc = crc32(calc_crc, (unsigned char*)"IDAT", 4); + calc_crc = crc32(calc_crc, (unsigned char*)chunk, length); + + file_read_ul(png, &orig_crc); + + if(orig_crc != calc_crc) + { + result = PNG_CRC_ERROR; + break; + } +#else + file_read_ul(png); +#endif + + result = png_inflate(png, chunk, length); + + if(result != PNG_NO_ERROR) break; + + file_read_ul(png, &length); + + if(length > old_len) + { + png_free(chunk); + chunk = png_alloc(length); + old_len = length; + } + + if(file_read(png, &type, 1, 4) != 4) + { + result = PNG_FILE_ERROR; + break; + } + + }while(type == *(unsigned int*)"IDAT"); + + if(type == *(unsigned int*)"IEND") + result = PNG_DONE; + + png_free(chunk); + png_end_inflate(png); + + return result; +} + +static int png_process_chunk(png_t* png) +{ + int result = PNG_NO_ERROR; + unsigned type; + unsigned length; + + file_read_ul(png, &length); + + if(file_read(png, &type, 1, 4) != 4) + return PNG_FILE_ERROR; + + if(type == *(unsigned int*)"IDAT") /* if we found an idat, all other idats should be followed with no other chunks in between */ + { + png->png_datalen = png->width * png->height * png->bpp + png->height; + png->png_data = png_alloc(png->png_datalen); + + if(!png->png_data) + return PNG_MEMORY_ERROR; + + return png_read_idat(png, length); + } + else if(type == *(unsigned int*)"IEND") + { + return PNG_DONE; + } + else + { + file_read(png, 0, 1, length + 4); /* unknown chunk */ + } + + return result; +} + +static void png_filter_sub(int stride, unsigned char* in, unsigned char* out, int len) +{ + int i; + unsigned char a = 0; + + for(i = 0; i < len; i++) + { + if(i >= stride) + a = out[i - stride]; + + out[i] = in[i] + a; + } +} + +static void png_filter_up(int stride, unsigned char* in, unsigned char* out, unsigned char* prev_line, int len) +{ + int i; + + if(prev_line) + { + for(i = 0; i < len; i++) + out[i] = in[i] + prev_line[i]; + } + else + memcpy(out, in, len); +} + +static void png_filter_average(int stride, unsigned char* in, unsigned char* out, unsigned char* prev_line, int len) +{ + int i; + unsigned char a = 0; + unsigned char b = 0; + unsigned int sum = 0; + + for(i = 0; i < len; i++) + { + if(prev_line) + b = prev_line[i]; + + if(i >= stride) + a = out[i - stride]; + + sum = a; + sum += b; + + out[i] = (char)(in[i] + sum/2); + } +} + +static unsigned char png_paeth(unsigned char a, unsigned char b, unsigned char c) +{ + int p = (int)a + b - c; + int pa = abs(p - a); + int pb = abs(p - b); + int pc = abs(p - c); + + int pr; + + if(pa <= pb && pa <= pc) + pr = a; + else if(pb <= pc) + pr = b; + else + pr = c; + + return (char)pr; +} + +static void png_filter_paeth(int stride, unsigned char* in, unsigned char* out, unsigned char* prev_line, int len) +{ + int i; + unsigned char a; + unsigned char b; + unsigned char c; + + for(i = 0; i < len; i++) + { + if(prev_line && i >= stride) + { + a = out[i - stride]; + b = prev_line[i]; + c = prev_line[i - stride]; + } + else + { + if(prev_line) + b = prev_line[i]; + else + b = 0; + + if(i >= stride) + a = out[i - stride]; + else + a = 0; + + c = 0; + } + + out[i] = in[i] + png_paeth(a, b, c); + } +} + +static int png_filter(png_t* png, unsigned char* data) +{ + + + return PNG_NO_ERROR; +} + +static int png_unfilter(png_t* png, unsigned char* data) +{ + unsigned i; + unsigned pos = 0; + unsigned outpos = 0; + unsigned char *filtered = png->png_data; + + int stride = png->bpp; + + while(pos < png->png_datalen) + { + unsigned char filter = filtered[pos]; + + pos++; + + if(png->depth == 16) + { + for(i = 0; i < png->width * stride; i+=2) + { + *(short*)(filtered+pos+i) = (filtered[pos+i] << 8) | filtered[pos+i+1]; + } + } + + switch(filter) + { + case 0: /* none */ + memcpy(data+outpos, filtered+pos, png->width * stride); + break; + case 1: /* sub */ + png_filter_sub(stride, filtered+pos, data+outpos, png->width * stride); + break; + case 2: /* up */ + if(outpos) + png_filter_up(stride, filtered+pos, data+outpos, data + outpos - (png->width*stride), png->width*stride); + else + png_filter_up(stride, filtered+pos, data+outpos, 0, png->width*stride); + break; + case 3: /* average */ + if(outpos) + png_filter_average(stride, filtered+pos, data+outpos, data + outpos - (png->width*stride), png->width*stride); + else + png_filter_average(stride, filtered+pos, data+outpos, 0, png->width*stride); + break; + case 4: /* paeth */ + if(outpos) + png_filter_paeth(stride, filtered+pos, data+outpos, data + outpos - (png->width*stride), png->width*stride); + else + png_filter_paeth(stride, filtered+pos, data+outpos, 0, png->width*stride); + break; + default: + return PNG_UNKNOWN_FILTER; + } + + outpos += png->width * stride; + pos += png->width * stride; + } + + return PNG_NO_ERROR; +} + +int png_get_data(png_t* png, unsigned char* data) +{ + int result = PNG_NO_ERROR; + + while(result == PNG_NO_ERROR) + { + result = png_process_chunk(png); + } + + if(result != PNG_DONE) + { + png_free(png->png_data); + return result; + } + + result = png_unfilter(png, data); + + png_free(png->png_data); + + return result; +} + +int png_set_data(png_t* png, unsigned width, unsigned height, char depth, int color, unsigned char* data) +{ + unsigned int i; + unsigned char *filtered; + png->width = width; + png->height = height; + png->depth = depth; + png->color_type = color; + png->bpp = png_get_bpp(png); + + filtered = png_alloc(width * height * png->bpp + height); + + for(i = 0; i < png->height; i++) + { + filtered[i*png->width*png->bpp+i] = 0; + memcpy(&filtered[i*png->width*png->bpp+i+1], data + i * png->width*png->bpp, png->width*png->bpp); + } + + png_filter(png, filtered); + png_write_ihdr(png); + png_write_idats(png, filtered); + + png_free(filtered); + return PNG_NO_ERROR; +} + + +char* png_error_string(int error) +{ + switch(error) + { + case PNG_NO_ERROR: + return "No error"; + case PNG_FILE_ERROR: + return "Unknown file error."; + case PNG_HEADER_ERROR: + return "No PNG header found. Are you sure this is a PNG?"; + case PNG_IO_ERROR: + return "Failure while reading file."; + case PNG_EOF_ERROR: + return "Reached end of file."; + case PNG_CRC_ERROR: + return "CRC or chunk length error."; + case PNG_MEMORY_ERROR: + return "Could not allocate memory."; + case PNG_ZLIB_ERROR: + return "zlib reported an error."; + case PNG_UNKNOWN_FILTER: + return "Unknown filter method used in scanline."; + case PNG_DONE: + return "PNG done"; + case PNG_NOT_SUPPORTED: + return "The PNG is unsupported by pnglite, too bad for you!"; + case PNG_WRONG_ARGUMENTS: + return "Wrong combination of arguments passed to png_open. You must use either a read_function or supply a file pointer to use."; + default: + return "Unknown error."; + }; +} diff --git a/shaders/basic.frag b/shaders/basic.frag new file mode 100644 index 0000000..808ef44 --- /dev/null +++ b/shaders/basic.frag @@ -0,0 +1,9 @@ +#version 120 + +uniform sampler2D sTexture; + +void main(void) { + vec4 tex = texture2D(sTexture, gl_TexCoord[0].st); + gl_FragColor = clamp(tex, 0.0, 1.0); + //gl_FragColor = vec4(gl_TexCoord[0].s, gl_TexCoord[0].t, 0.0, 1.0); +} diff --git a/shaders/basic.vert b/shaders/basic.vert new file mode 100644 index 0000000..249e86f --- /dev/null +++ b/shaders/basic.vert @@ -0,0 +1,6 @@ +#version 120 + +void main() { + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = ftransform(); +}