Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Seeker

Pages: 1
1
Function Peer Review / Re: sprite_create_from_screen
« on: June 19, 2013, 03:47:38 PM »
Hey, Josh!

Good thinking. I edited the code with your suggestions. The function can now be used in a Draw event without infinitely looping when view_enabled.

Although, the view hack still forces a screen_redraw(), as I couldn't figure another way at the moment. So if someone uses the function in a Draw event with view_enabled, here are two examples of how they might do that:

Create Event (both examples):

Code: [Select]
createSprite = false;

Draw Event (example 1):

Code: [Select]
draw_set_color(c_blue);
draw_rectangle(0,0,32,32,0);
//
if (createSprite)
{
    createSprite = false;
    variant spr = sprite_create_from_screen(0,0,32,32,false,false,0,0);
    //
    if (sprite_exists(spr)) show_message("Do something with new sprite!");
}

Draw Event (example 2)

Code: [Select]
if (createSprite)
{
    draw_set_color(c_green);
    draw_rectangle(0,0,32,32,0);
    //
    variant spr = sprite_create_from_screen(0,0,32,32,false,false,0,0);
    createSprite = false; // Note how this line comes AFTER sprite_create_from_screen() in this example. If it didn't and view_enabled is true, the rectangle wouldn't be captured in the created sprite due to the forced screen_redraw() for views. See why???
    //
    if (sprite_exists(spr)) show_message("Do something with new sprite!");
}

In testing, this sprite_create_from_screen() function will actually capture the image in any one view, but I couldn't know about multiple views in one image, as it seems (in quick testing) enigma has a few kinks in rendering multiple views. For example, I just tried setting up two views side by side, splitting the screen in half, but the left viewport was always a garbled image.

For the window_get_width/height() part, I changed them to use the OpenGL viewport values directly. The "viewportData[3] - y - hFull" and pixel data flipping was necessary for me to get the correct result, but I know very little about OpenGL actually, so perhaps there's another way.

Thanks for the great work you've done so far with ENIGMA.

2
Function Peer Review / sprite_create_from_screen
« on: June 18, 2013, 02:52:23 PM »
Hello, lovely people.

I put this together for you. The only items that need implementation are the "smooth" and "preload" params, but this is ready to run.

Enjoy.

Code: [Select]
/********************************************************************************\
**                                                                              **
**  Copyright (C) 2013 Seeker                                                   **
**                                                                              **
**  This file is a part of the ENIGMA Development Environment.                  **
**                                                                              **
**                                                                              **
**  ENIGMA is free software: you can redistribute it and/or modify it under the **
**  terms of the GNU General Public License as published by the Free Software   **
**  Foundation, version 3 of the license or any later version.                  **
**                                                                              **
**  This application and its source code is distributed AS-IS, WITHOUT ANY      **
**  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS   **
**  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more       **
**  details.                                                                    **
**                                                                              **
**  You should have recieved a copy of the GNU General Public License along     **
**  with this code. If not, see <http://www.gnu.org/licenses/>                  **
**                                                                              **
**  ENIGMA is an environment designed to create games and other programs with a **
**  high-level, fully compilable language. Developers of ENIGMA or anything     **
**  associated with ENIGMA are in no way responsible for its users or           **
**  applications created by its users, or damages caused by the environment     **
**  or programs made in the environment.                                        **
**                                                                              **
\********************************************************************************/

// Includes

#include <string.h>

#include "Universal_System/nlpo2.h"



// Declarations

// gm7-
int sprite_create_from_screen(unsigned int x, unsigned int y, unsigned int w, unsigned int h, bool precise, bool transparent, bool smooth, bool preload, int xorig, int yorig);

// gm8+
int sprite_create_from_screen(unsigned int x, unsigned int y, unsigned int w, unsigned int h, bool removeback, bool smooth, int xorig, int yorig);



// Definitions

// NOTE: The only items that need implementation are the "smooth" and "preload" params
int sprite_create_from_screen(unsigned int x, unsigned int y, unsigned int w, unsigned int h, bool precise, bool transparent, bool smooth, bool preload, int xorig, int yorig)
{

static bool viewRedrawHack = false; // currently needed so this function can safely be called in a Draw event, since this function forces a screen_redraw() if view_enabled
if (view_enabled && viewRedrawHack) return -1;

//

w = max(w,1);
h = max(h,1);

int wFull = nlpo2dc(w) + 1,
hFull = nlpo2dc(h) + 1,
stride = wFull * 4;

//

unsigned char * swapline = new unsigned char[stride](),
              * pxdata = new unsigned char[stride*hFull]();

if (!swapline || !pxdata) return -1;

//

int viewportData[4];
glGetIntegerv(GL_VIEWPORT, viewportData);

if (view_enabled) // hacking views like the NSA
{
bool viewVisPrev[8];

for (int i = 0; i < 8; i++)
{
viewVisPrev[i] = view_visible[i];
view_visible[i] = (i == 0);
}

int wview0Prev = view_wview,
hview0Prev = view_hview;

view_wview = /*window_get_width()*/viewportData[2];
view_hview = /*window_get_height()*/viewportData[3];
viewRedrawHack = true;
        screen_redraw();
        viewRedrawHack = false;
view_wview = wview0Prev;
view_hview = hview0Prev;

for (int i = 0; i < 8; i++) view_visible[i] = viewVisPrev[i];
}

glReadPixels(x, /*window_get_height()*/viewportData[3] - y - hFull, wFull, hFull, GL_RGBA, GL_UNSIGNED_BYTE, pxdata);

//

for (int row = 0; row < hFull/2; row++) // flip pixels vertically
{
memcpy(swapline, pxdata + row*stride, stride);
memcpy(pxdata + row*stride, pxdata + (hFull-row-1)*stride, stride);
memcpy(pxdata + (hFull-row-1)*stride, swapline, stride);
}

delete[] swapline;

//

int bbl = 0,
bbt = 0,
bbr = w - 1,
bbb = h - 1;

if (transparent)
{
unsigned char* pxdataTrans = &pxdata[(h-1)*stride]; // transparency pixel data (bottom-left pixel)

bool bblGot = false,
bbtGot = false,
bbrGot = false,
bbbGot = false;

// remove transparent color, and get bbox top and bottom
for (int yy = 0; yy < h; yy++)
{
bool bbtRowEmpty = true,
bbbRowEmpty = true;

for (int xx = 0; xx < w; xx++)
{
int xo = xx*4,
bbtOffset = yy*stride + xo;

if (memcmp(&pxdata[bbtOffset], pxdataTrans, 3) == 0) pxdata[bbtOffset+3] = 0; // a transparent pixel
else bbtRowEmpty = false;

if (!bbbGot && memcmp(&pxdata[(h-1-yy)*stride + xo], pxdataTrans, 3) != 0) bbbRowEmpty = false;
}

if (!bbtGot)
{
if (bbtRowEmpty) bbt++;
else bbtGot = true;
}

if (!bbbGot)
{
if (bbbRowEmpty) bbb--;
else bbbGot = true;
}
}

// now just get bbox left and right
for (int xx = 0; xx < w; xx++)
{
bool bblColEmpty = true,
bbrColEmpty = true;

for (int yy = 0; yy < h; yy++)
{
int xo = xx*4 + 3;
if (!bblGot && pxdata[yy*stride + xo] != 0) bblColEmpty = false;
if (!bbrGot && pxdata[(h-1-yy)*stride + xo] != 0) bbrColEmpty = false;
}

if (!bblGot)
{
if (bblColEmpty) bbl++;
else bblGot = true;
}

if (!bbrGot)
{
if (bbrColEmpty) bbr--;
else bbrGot = true;
}

if (bblGot && bbrGot) break;
}

// if the entire image is transparent, doing this to keep bboxes from being off by 1 pixel
bbl = min(bbl, w - 1);
bbt = min(bbt, h - 1);
bbr = max(bbr, 0);
bbb = max(bbb, 0);
}

// show_message("l: " + string(bbl) + " t: " + string(bbt) + " r: " + string(bbr) + " b: " + string(bbb));

// mostly sprite_add_to_index() code from spritestruct.cpp follows, so may want to refactor

enigma::spritestructarray_reallocate();
enigma::sprite *ns = enigma::spritestructarray[enigma::sprite_idmax] = new enigma::sprite();

// if (!ns) return -1; //

ns->id = enigma::sprite_idmax;
ns->subcount = 1;
ns->width = w;
ns->height = h;

ns->bbox.bottom = bbb;
ns->bbox.left = bbl;
ns->bbox.top = bbt;
ns->bbox.right = bbr;

ns->bbox_relative.bottom = bbb - yorig;
ns->bbox_relative.left = bbl - xorig;
ns->bbox_relative.top = bbt - yorig;
ns->bbox_relative.right = bbr - xorig;

ns->xoffset = (int)xorig;
ns->yoffset = (int)yorig;

ns->texturearray = new int[1];
ns->texturearray[0] = enigma::graphics_create_texture(wFull, hFull, pxdata);

ns->texbordxarray = new double[1];
ns->texbordxarray[0] = (double) w/wFull;
ns->texbordyarray = new double[1];
ns->texbordyarray[0] = (double) h/hFull;

ns->colldata = new void*[1];
enigma::collision_type coll_type = precise ? enigma::ct_precise : enigma::ct_bbox;
ns->colldata[0] = get_collision_mask(ns, (unsigned char *)pxdata, coll_type);

delete[] pxdata;

//

return enigma::sprite_idmax++;

}

inline int sprite_create_from_screen(unsigned int x, unsigned int y, unsigned int w, unsigned int h, bool removeback, bool smooth, int xorig, int yorig)
{
return sprite_create_from_screen(x, y, w, h, /*precise*/removeback, /*transparent*/removeback, smooth, /*preload*/true, xorig, yorig);
}

Pages: 1