summaryrefslogtreecommitdiffstats
path: root/dev/MinGfx/src/texture2d.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dev/MinGfx/src/texture2d.cc')
-rw-r--r--dev/MinGfx/src/texture2d.cc232
1 files changed, 232 insertions, 0 deletions
diff --git a/dev/MinGfx/src/texture2d.cc b/dev/MinGfx/src/texture2d.cc
new file mode 100644
index 0000000..230ad5f
--- /dev/null
+++ b/dev/MinGfx/src/texture2d.cc
@@ -0,0 +1,232 @@
+/*
+ Copyright (c) 2017,2018 Regents of the University of Minnesota.
+ All Rights Reserved.
+ See corresponding header file for details.
+ */
+
+#include "texture2d.h"
+#include "platform.h"
+
+#pragma warning (push)
+#pragma warning (disable : 6001)
+#pragma warning (disable : 6011)
+#pragma warning (disable : 6262)
+#pragma warning (disable : 6385)
+#pragma warning (disable : 6387)
+#pragma warning (disable : 26450)
+#pragma warning (disable : 26451)
+#pragma warning (disable : 26453)
+#pragma warning (disable : 26495)
+#pragma warning (disable : 26812)
+
+#ifdef WIN32
+ // this is not needed on OSX or Linux, it must pick up the symbols from
+ // libnanogui.so, but it appears to be needed on Windows.
+ #define STB_IMAGE_IMPLEMENTATION
+#endif
+#include <stb_image.h>
+
+#pragma warning (pop)
+
+#include <iostream>
+
+
+namespace mingfx {
+
+
+
+Texture2D::Texture2D(GLenum wrapMode, GLenum filterMode) :
+ dataType_(GL_UNSIGNED_BYTE), data_ubyte_(NULL), data_float_(NULL),
+ width_(0), height_(0), handleMemInternally_(true), texID_(0),
+ wrapMode_(wrapMode), filterMode_(filterMode)
+{
+}
+
+Texture2D::~Texture2D() {
+
+ // Mem handled internally is always of type data_ubyte_ because that is
+ // what the stbi image loading library returns
+ if ((handleMemInternally_) && (data_ubyte_ != NULL)) {
+ // BUG, TODO: Not sure why the call below does not seem to work.
+ // There will be a mem leak unless we can call this somehow.
+ //stbi_image_free(data_);
+ }
+
+ // This is how to delete GL's version of the texture on the GPU
+ // but you have to be very careful with this. For example, if we cause
+ // C++ to make a tmp copy of the Texture2D or we do an assignment tex1=tex2
+ // we now have two Texture2D objects pointing to the same OpenGL texture id.
+ // If one of them is deleted before the other, then the other will not be
+ // able to draw itself because the OpenGL tex id will be invalid. For now,
+ // this is "addressed" by simply skipping the glDeleteTextures call. This
+ // leads to some wasted OpenGL memory, and that would be a good thing to
+ // fix in the future, maybe via a shared_ptr or static refcount that maps
+ // opengl texids to a count of Texture2D objects that reference them. Then,
+ // only delete the opengl tex if the refcount would go to 0.
+ //glDeleteTextures(1, &texID_);
+}
+
+
+bool Texture2D::InitFromFile(const std::string &filename) {
+ handleMemInternally_ = true;
+ dataType_ = GL_UNSIGNED_BYTE;
+
+
+ std::cout << "Loading texture from file: " << filename << std::endl;
+
+ if (Platform::FileExists(filename)) {
+ stbi_set_unpremultiply_on_load(1);
+ stbi_convert_iphone_png_to_rgb(1);
+ int numChannels;
+ data_ubyte_ = stbi_load(filename.c_str(), &width_, &height_, &numChannels, 4);
+ if (data_ubyte_ == NULL) {
+ std::cerr << "Texture2D: Failed to load file " << filename << " - " << stbi_failure_reason() << std::endl;
+ return false;
+ }
+ }
+ else {
+ std::cerr << "Texture2D: File " << filename << " does not exist." << std::endl;
+ return false;
+ }
+
+ return InitOpenGL();
+}
+
+bool Texture2D::InitFromBytes(int width, int height, const unsigned char * data) {
+ handleMemInternally_ = false;
+ width_ = width;
+ height_ = height;
+ data_ubyte_ = data;
+ dataType_ = GL_UNSIGNED_BYTE;
+
+ return InitOpenGL();
+}
+
+bool Texture2D::InitFromFloats(int width, int height, const float * data) {
+ handleMemInternally_ = false;
+ width_ = width;
+ height_ = height;
+ data_float_ = data;
+ dataType_ = GL_FLOAT;
+
+ return InitOpenGL();
+}
+
+bool Texture2D::InitOpenGL() {
+ glGenTextures(1, &texID_);
+ glBindTexture(GL_TEXTURE_2D, texID_);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterMode_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterMode_);
+
+ if (dataType_ == GL_UNSIGNED_BYTE) {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, dataType_, data_ubyte_);
+ }
+ else if (dataType_ == GL_FLOAT) {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, dataType_, data_float_);
+ }
+ else {
+ std::cerr << "Texture2D: Unsupported texture data type " << dataType_ << "." << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+
+bool Texture2D::UpdateFromBytes(const unsigned char * data) {
+ dataType_ = GL_UNSIGNED_BYTE;
+ data_ubyte_ = data;
+ glBindTexture(GL_TEXTURE_2D, texID_);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, dataType_, data_ubyte_);
+ // presumably glTexSubImage2D is faster, but this crashes on OSX for some reason
+ //glActiveTexture(texID_);
+ //glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_RGBA, dataType_, data_ubyte_);
+ return true;
+}
+
+bool Texture2D::UpdateFromFloats(const float * data) {
+ dataType_ = GL_FLOAT;
+ data_float_ = data;
+ glBindTexture(GL_TEXTURE_2D, texID_);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, dataType_, data_float_);
+ // presumably glTexSubImage2D is faster, but this crashes on OSX for some reason
+ //glActiveTexture(texID_);
+ //glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_RGBA, dataType_, data_ubyte_);
+ return true;
+}
+
+
+
+int Texture2D::width() const {
+ return width_;
+}
+
+int Texture2D::height() const {
+ return height_;
+}
+
+
+GLuint Texture2D::opengl_id() const {
+ if (!initialized()) {
+ std::cerr << "Texture2D: Warning, accessing opengl_id() before it has been initialized." << std::endl
+ << "You might be calling opengl_id() before InitOpenGL(). Or, there might have been a" << std::endl
+ << "error loading texture data or binding it to OpenGL." << std::endl;
+ }
+ return texID_;
+}
+
+GLenum Texture2D::wrap_mode() const {
+ return wrapMode_;
+}
+
+GLenum Texture2D::filter_mode() const {
+ return filterMode_;
+}
+
+void Texture2D::set_wrap_mode(GLenum wrapMode) {
+ wrapMode_ = wrapMode;
+ glBindTexture(GL_TEXTURE_2D, texID_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode_);
+}
+
+void Texture2D::set_filter_mode(GLenum filterMode) {
+ filterMode_ = filterMode;
+ glBindTexture(GL_TEXTURE_2D, texID_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterMode_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterMode_);
+}
+
+bool Texture2D::initialized() const {
+ return texID_ != 0;
+}
+
+
+Color Texture2D::Pixel(int x, int y) const {
+ int index = y*4*width() + x*4;
+
+ if (dataType_ == GL_UNSIGNED_BYTE) {
+ unsigned char r = data_ubyte_[index+0];
+ unsigned char g = data_ubyte_[index+1];
+ unsigned char b = data_ubyte_[index+2];
+ unsigned char a = data_ubyte_[index+3];
+ return Color((float)r/255.0f, (float)g/255.0f, (float)b/255.0f, (float)a/255.0f);
+ }
+ else if (dataType_ == GL_FLOAT) {
+ float r = data_float_[index+0];
+ float g = data_float_[index+1];
+ float b = data_float_[index+2];
+ float a = data_float_[index+3];
+ return Color(r, g, b, a);
+ }
+ else {
+ std::cerr << "Texture2D: Unsupported texture data type " << dataType_ << "." << std::endl;
+ return Color();
+ }
+}
+
+} // end namespace
+