Просмотр исходного кода

Merge pull request #1077 from rcmaniac25/next

Screenshot capability by creating an Image from a FrameBuffer
Sean Paul Taylor 12 лет назад
Родитель
Сommit
36b1dc985d

+ 24 - 0
gameplay/src/FrameBuffer.cpp

@@ -269,6 +269,30 @@ FrameBuffer* FrameBuffer::bind()
     return previousFrameBuffer;
 }
 
+void FrameBuffer::getScreenshot(Image* image)
+{
+	//While possible to have a non-static getScreenshot function, it would require the expensive operation 
+	//of binding the FrameBuffer, reading the pixels, then rebinding the original FrameBuffer. This is faster.(
+
+	GP_ASSERT(image);
+	GP_ASSERT(image->getFormat() == Image::RGBA);
+
+	unsigned int width = _currentFrameBuffer->getWidth();
+	unsigned int height = _currentFrameBuffer->getHeight();
+
+	if (image->getWidth() == width && image->getHeight() == height)
+		GL_ASSERT( glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image->getData()) );
+}
+
+Image* FrameBuffer::createScreenshot()
+{
+	Image* screenshot = Image::create(_currentFrameBuffer->getWidth(), _currentFrameBuffer->getHeight(), Image::RGBA, NULL);
+
+	getScreenshot(screenshot);
+
+	return screenshot;
+}
+
 FrameBuffer* FrameBuffer::bindDefault()
 {
     GL_ASSERT( glBindFramebuffer(GL_FRAMEBUFFER, _defaultFrameBuffer->_handle) );

+ 18 - 0
gameplay/src/FrameBuffer.h

@@ -4,6 +4,7 @@
 #include "Base.h"
 #include "RenderTarget.h"
 #include "DepthStencilTarget.h"
+#include "Image.h"
 
 namespace gameplay
 {
@@ -151,6 +152,23 @@ public:
      */
     FrameBuffer* bind();
 
+	/**
+	 * Records a screenshot of what is stored on the current FrameBuffer.
+	 * 
+	 * @return A screenshot of the current framebuffer's content.
+	 */
+	static Image* createScreenshot();
+
+	/**
+	 * Records a screenshot of what is stored on the current FrameBuffer to an Image.
+	 * 
+	 * The Image must be the same size as the FrameBuffer, otherwise the operation will fail.
+	 * The Image must be format RGBA.
+	 * 
+	 * @param image The Image to write the current framebuffer's content to.
+	 */
+	static void getScreenshot(Image* image);
+
     /**
      * Binds the default FrameBuffer for rendering to the display.
      *

+ 30 - 0
gameplay/src/Image.cpp

@@ -107,6 +107,36 @@ Image* Image::create(const char* path)
     return image;
 }
 
+Image* Image::create(unsigned int width, unsigned int height, Image::Format format, unsigned char* data)
+{
+	GP_ASSERT(width > 0 && height > 0);
+	GP_ASSERT(format >= RGB && format <= RGBA);
+
+	unsigned int pixelSize = 0;
+	switch(format)
+	{
+	case Image::RGB:
+		pixelSize = 3;
+		break;
+	case Image::RGBA:
+		pixelSize = 4;
+		break;
+	}
+
+	Image* image = new Image();
+
+	unsigned int dataSize = width * height * pixelSize;
+
+	image->_width = width;
+	image->_height = height;
+	image->_format = format;
+	image->_data = new unsigned char[dataSize];
+	if (data)
+		memcpy(image->_data, data, dataSize);
+
+	return image;
+}
+
 Image::Image()
 {
     // Unused

+ 12 - 0
gameplay/src/Image.h

@@ -31,6 +31,18 @@ public:
      */
     static Image* create(const char* path);
 
+	/**
+     * Creates an image from the data provided
+     * 
+     * @param width The width of the image data.
+	 * @param height The height of the image data.
+	 * @param format The format of the image data.
+	 * @param data The image data. If NULL, the data will be allocated.
+     * @return The newly created image.
+     * @script{create}
+     */
+	static Image* create(unsigned int width, unsigned int height, Format format, unsigned char* data = NULL);
+
     /**
      * Gets the image's raw pixel data.
      * 

+ 79 - 0
gameplay/src/lua/lua_FrameBuffer.cpp

@@ -32,9 +32,11 @@ void luaRegister_FrameBuffer()
     {
         {"bindDefault", lua_FrameBuffer_static_bindDefault},
         {"create", lua_FrameBuffer_static_create},
+        {"createScreenshot", lua_FrameBuffer_static_createScreenshot},
         {"getCurrent", lua_FrameBuffer_static_getCurrent},
         {"getFrameBuffer", lua_FrameBuffer_static_getFrameBuffer},
         {"getMaxRenderTargets", lua_FrameBuffer_static_getMaxRenderTargets},
+        {"getScreenshot", lua_FrameBuffer_static_getScreenshot},
         {NULL, NULL}
     };
     std::vector<std::string> scopePath;
@@ -760,6 +762,43 @@ int lua_FrameBuffer_static_create(lua_State* state)
     return 0;
 }
 
+int lua_FrameBuffer_static_createScreenshot(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 0:
+        {
+            void* returnPtr = (void*)FrameBuffer::createScreenshot();
+            if (returnPtr)
+            {
+                gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                object->instance = returnPtr;
+                object->owns = false;
+                luaL_getmetatable(state, "Image");
+                lua_setmetatable(state, -2);
+            }
+            else
+            {
+                lua_pushnil(state);
+            }
+
+            return 1;
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 0).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_FrameBuffer_static_getCurrent(lua_State* state)
 {
     // Get the number of parameters.
@@ -871,4 +910,44 @@ int lua_FrameBuffer_static_getMaxRenderTargets(lua_State* state)
     return 0;
 }
 
+int lua_FrameBuffer_static_getScreenshot(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA || lua_type(state, 1) == LUA_TTABLE || lua_type(state, 1) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                bool param1Valid;
+                gameplay::ScriptUtil::LuaArray<Image> param1 = gameplay::ScriptUtil::getObjectPointer<Image>(1, "Image", false, &param1Valid);
+                if (!param1Valid)
+                {
+                    lua_pushstring(state, "Failed to convert parameter 1 to type 'Image'.");
+                    lua_error(state);
+                }
+
+                FrameBuffer::getScreenshot(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_FrameBuffer_static_getScreenshot - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 }

+ 2 - 0
gameplay/src/lua/lua_FrameBuffer.h

@@ -21,9 +21,11 @@ int lua_FrameBuffer_setDepthStencilTarget(lua_State* state);
 int lua_FrameBuffer_setRenderTarget(lua_State* state);
 int lua_FrameBuffer_static_bindDefault(lua_State* state);
 int lua_FrameBuffer_static_create(lua_State* state);
+int lua_FrameBuffer_static_createScreenshot(lua_State* state);
 int lua_FrameBuffer_static_getCurrent(lua_State* state);
 int lua_FrameBuffer_static_getFrameBuffer(lua_State* state);
 int lua_FrameBuffer_static_getMaxRenderTargets(lua_State* state);
+int lua_FrameBuffer_static_getScreenshot(lua_State* state);
 
 void luaRegister_FrameBuffer();
 

+ 101 - 16
gameplay/src/lua/lua_Image.cpp

@@ -292,27 +292,112 @@ int lua_Image_static_create(lua_State* state)
     {
         case 1:
         {
-            if ((lua_type(state, 1) == LUA_TSTRING || lua_type(state, 1) == LUA_TNIL))
+            do
             {
-                // Get parameter 1 off the stack.
-                const char* param1 = gameplay::ScriptUtil::getString(1, false);
-
-                void* returnPtr = (void*)Image::create(param1);
-                if (returnPtr)
+                if ((lua_type(state, 1) == LUA_TSTRING || lua_type(state, 1) == LUA_TNIL))
                 {
-                    gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
-                    object->instance = returnPtr;
-                    object->owns = true;
-                    luaL_getmetatable(state, "Image");
-                    lua_setmetatable(state, -2);
+                    // Get parameter 1 off the stack.
+                    const char* param1 = gameplay::ScriptUtil::getString(1, false);
+
+                    void* returnPtr = (void*)Image::create(param1);
+                    if (returnPtr)
+                    {
+                        gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                        object->instance = returnPtr;
+                        object->owns = true;
+                        luaL_getmetatable(state, "Image");
+                        lua_setmetatable(state, -2);
+                    }
+                    else
+                    {
+                        lua_pushnil(state);
+                    }
+
+                    return 1;
                 }
-                else
+            } while (0);
+
+            lua_pushstring(state, "lua_Image_static_create - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        case 3:
+        {
+            do
+            {
+                if (lua_type(state, 1) == LUA_TNUMBER &&
+                    lua_type(state, 2) == LUA_TNUMBER &&
+                    (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL))
                 {
-                    lua_pushnil(state);
+                    // Get parameter 1 off the stack.
+                    unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 1);
+
+                    // Get parameter 2 off the stack.
+                    unsigned int param2 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                    // Get parameter 3 off the stack.
+                    Image::Format param3 = (Image::Format)lua_enumFromString_ImageFormat(luaL_checkstring(state, 3));
+
+                    void* returnPtr = (void*)Image::create(param1, param2, param3);
+                    if (returnPtr)
+                    {
+                        gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                        object->instance = returnPtr;
+                        object->owns = true;
+                        luaL_getmetatable(state, "Image");
+                        lua_setmetatable(state, -2);
+                    }
+                    else
+                    {
+                        lua_pushnil(state);
+                    }
+
+                    return 1;
                 }
+            } while (0);
 
-                return 1;
-            }
+            lua_pushstring(state, "lua_Image_static_create - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        case 4:
+        {
+            do
+            {
+                if (lua_type(state, 1) == LUA_TNUMBER &&
+                    lua_type(state, 2) == LUA_TNUMBER &&
+                    (lua_type(state, 3) == LUA_TSTRING || lua_type(state, 3) == LUA_TNIL) &&
+                    (lua_type(state, 4) == LUA_TTABLE || lua_type(state, 4) == LUA_TLIGHTUSERDATA))
+                {
+                    // Get parameter 1 off the stack.
+                    unsigned int param1 = (unsigned int)luaL_checkunsigned(state, 1);
+
+                    // Get parameter 2 off the stack.
+                    unsigned int param2 = (unsigned int)luaL_checkunsigned(state, 2);
+
+                    // Get parameter 3 off the stack.
+                    Image::Format param3 = (Image::Format)lua_enumFromString_ImageFormat(luaL_checkstring(state, 3));
+
+                    // Get parameter 4 off the stack.
+                    gameplay::ScriptUtil::LuaArray<unsigned char> param4 = gameplay::ScriptUtil::getUnsignedCharPointer(4);
+
+                    void* returnPtr = (void*)Image::create(param1, param2, param3, param4);
+                    if (returnPtr)
+                    {
+                        gameplay::ScriptUtil::LuaObject* object = (gameplay::ScriptUtil::LuaObject*)lua_newuserdata(state, sizeof(gameplay::ScriptUtil::LuaObject));
+                        object->instance = returnPtr;
+                        object->owns = true;
+                        luaL_getmetatable(state, "Image");
+                        lua_setmetatable(state, -2);
+                    }
+                    else
+                    {
+                        lua_pushnil(state);
+                    }
+
+                    return 1;
+                }
+            } while (0);
 
             lua_pushstring(state, "lua_Image_static_create - Failed to match the given parameters to a valid function signature.");
             lua_error(state);
@@ -320,7 +405,7 @@ int lua_Image_static_create(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_pushstring(state, "Invalid number of parameters (expected 1, 3 or 4).");
             lua_error(state);
             break;
         }