Jump to content


Photo

Need a dll that gets array of screen pixels


  • Please log in to reply
41 replies to this topic

#1 storkEXEC

storkEXEC

    GMC Member

  • New Member
  • 365 posts
  • Version:GM8

Posted 14 September 2011 - 01:54 PM

I need a DLL that uses four arguments (x,y,width and height) and gets whatever pixels are in that bounding box and returns them as a string (each pixel would be listed in a sequence, separated by spaces, sequenced as reading a book.)

So lets pretend c_green is represented by 10000, and pink is 20000. Pretend this is a 2x2 image.

Posted Image

It would return a string of
0 10000 20000 0

The other DLL's that get pixels from the screen I can't use because I have to call them pixel by pixel and calling DLL's is too slow.

Alternatively, is there a DLL that can be used to speed up DLL's (for example, I have to call DLL's a lot, so a DLL that could use a repeat statement and call them for me?)

Edited by storkEXEC, 14 September 2011 - 02:02 PM.

  • 0

#2 zmaj

zmaj

    GMC Member

  • GMC Member
  • 323 posts

Posted 14 September 2011 - 05:36 PM

well GM have such command itself draw_get_pixel(x,y)
so, if you need values of an area, make loop for that area...

Oh I did not read all... yes you need such dkll :)

Edited by zmaj, 14 September 2011 - 05:50 PM.

  • 0

#3 storkEXEC

storkEXEC

    GMC Member

  • New Member
  • 365 posts
  • Version:GM8

Posted 14 September 2011 - 06:06 PM

well GM have such command itself draw_get_pixel(x,y)
so, if you need values of an area, make loop for that area...

Oh I did not read all... yes you need such dkll :)

:turned:
  • 0

#4 kibblesbob

kibblesbob

    "Xarrot Studios"

  • GMC Member
  • 210 posts
  • Version:GM:Studio

Posted 14 September 2011 - 06:53 PM

i have the same problem. I would love to help but I've looked everywhere for something like this too. sorry
  • 0

#5 zmaj

zmaj

    GMC Member

  • GMC Member
  • 323 posts

Posted 15 September 2011 - 10:10 AM

i have the same problem. I would love to help but I've looked everywhere for something like this too. sorry


there is solution...

Here is group who made dll with all gm functions in dll...
So, ask him to add new one function ( draw_get_pixel()) with loop for an aria ...
That mean, that will be dll, with function you need, and still Game Maker... :)
  • 0

#6 paul23

paul23

    GMC Member

  • Global Moderators
  • 3355 posts
  • Version:GM8

Posted 15 September 2011 - 10:41 AM

The problem is that getting the colour of a pixel is slow.. Doing this over a large area is even worse.

The better way would be to actually store the pixel information inside an array, so to store those during loading of the images. As this is not done by gamemaker, you'll have to look for a dll that completely handles the graphics itself.
  • 0

#7 SyncViews

SyncViews

    GMC Member

  • GMC Member
  • 392 posts

Posted 15 September 2011 - 10:55 AM

It is possible for a DLL to do what he wants to do. A lot of the overhead for getting pixels from display/direct3d/siimilar things is the overhead of accessing the resource to start with. Once thats done, accessing many pixels isnt that much slower (just imagen how slow things like print screen, and those video recorders would be if it was a simple linear function!), which can then be encoded in some kind of string like hes asking.

I think the issue here is a slight lack of incentive to make it.

Edited by SyncViews, 15 September 2011 - 10:56 AM.

  • 0

#8 zmaj

zmaj

    GMC Member

  • GMC Member
  • 323 posts

Posted 15 September 2011 - 10:55 AM

The problem is that getting the colour of a pixel is slow.. Doing this over a large area is even worse.

The better way would be to actually store the pixel information inside an array, so to store those during loading of the images. As this is not done by gamemaker, you'll have to look for a dll that completely handles the graphics itself.




Yes that is another solution///
I was using some dll for painting..they have ability to paint in one color selected area.. pixels,in that area, with some other colors was stay intact...
I know there is not exactly they need, but maybe if they make some comaprsion , can got result...
  • 0

#9 storkEXEC

storkEXEC

    GMC Member

  • New Member
  • 365 posts
  • Version:GM8

Posted 15 September 2011 - 01:17 PM


The problem is that getting the colour of a pixel is slow.. Doing this over a large area is even worse.

The better way would be to actually store the pixel information inside an array, so to store those during loading of the images. As this is not done by gamemaker, you'll have to look for a dll that completely handles the graphics itself.




Yes that is another solution///
I was using some dll for painting..they have ability to paint in one color selected area.. pixels,in that area, with some other colors was stay intact...
I know there is not exactly they need, but maybe if they make some comaprsion , can got result...


Yep I have that DLL, unfortunately it doesn't have a a per-area pixel function, and it's getpixel function is slower than most getpixel DLLs.

paul23, you are right, the problem is no such dll exists, that is why I have made this topic :D

I will pay 20$ to the first person who can make this dll, while keeping the framerate at 60 or higher. (paypal only) If more than one person makes the DLL in the same day then the fastest, meets the requirements and most compatible one wins. I will pay, but only if the DLL is what I'm looking for (for example, if you make a DLL that searches for a specific color that's not what I'm looking for.)

Edited by storkEXEC, 15 September 2011 - 01:20 PM.

  • 0

#10 IceMetalPunk

IceMetalPunk

    InfiniteIMPerfection

  • Retired Staff
  • 9259 posts
  • Version:Unknown

Posted 15 September 2011 - 04:43 PM

I'm still having issues with my IDE, so I have no idea whether this will work or not (and I can't compile...anything). But I believe this would do what you want (in C++):

#define GMString extern "C" __declspec(dllexport) char*
#include <string>
#include <stdlib.h>
#include <windows.h>

GMString getPixels(double x, double y, double w, double h) {
  HDC dc=CreateDC("DISPLAY", NULL, NULL, NULL);
  string str;
  
  for (int xx=x; xx<x+w; xx++) {
    for (int yy=y; yy<y+h; yy++) {
      COLORREF c=GetPixel(dc, xx, yy);
      str+=itoa((int)c, 10)+" ";
    }
  }
  
  DeleteDC(dc);        
  
  return str.c_str();
}

I don't often work with device contexts, but I think it should be fine. Maybe someone who has a working IDE/compiler can compile it into a DLL for you.

-IMP

Edited by IceMetalPunk, 15 September 2011 - 04:45 PM.

  • 1

#11 storkEXEC

storkEXEC

    GMC Member

  • New Member
  • 365 posts
  • Version:GM8

Posted 15 September 2011 - 05:19 PM

I'm still having issues with my IDE, so I have no idea whether this will work or not (and I can't compile...anything). But I believe this would do what you want (in C++):

#define GMString extern "C" __declspec(dllexport) char*
#include <string>
#include <stdlib.h>
#include <windows.h>

GMString getPixels(double x, double y, double w, double h) {
  HDC dc=CreateDC("DISPLAY", NULL, NULL, NULL);
  string str;
  
  for (int xx=x; xx<x+w; xx++) {
    for (int yy=y; yy<y+h; yy++) {
      COLORREF c=GetPixel(dc, xx, yy);
      str+=itoa((int)c, 10)+" ";
    }
  }
  
  DeleteDC(dc);        
  
  return str.c_str();
}

I don't often work with device contexts, but I think it should be fine. Maybe someone who has a working IDE/compiler can compile it into a DLL for you.

-IMP


I will try, but it probably won't work. How do you compile a DLL? I have Dev C++, do I need a header or something? What do I put in it? If your compiler isn't working, there are plenty of free compilers on the net. If I can get it to work I'll give you 20$, but if not I'll have to let you or someone else compile it for me. Try a library or school computer. Otherwise, to be fair, I'll have to share the 20$ with whoever it is that compiled it.

Edited by storkEXEC, 15 September 2011 - 05:20 PM.

  • 0

#12 IceMetalPunk

IceMetalPunk

    InfiniteIMPerfection

  • Retired Staff
  • 9259 posts
  • Version:Unknown

Posted 15 September 2011 - 06:06 PM

Nah, I don't need the money ;) .

I have Dev-C++ as well, but lately it's been kind of...disobedient :lol:. Maybe your copy would work. In Dev-C++, just go to File->New->Project and choose DLL. Close the dll.h tab, as you won't need that. Replace everything in the main source file with my code, and click Execute->Compile. That should create the DLL assuming no errors.

All my school's computers either run *nix systems or use Cygwin to compile under *nix conditions, so the required Windows headers don't exist on those computers. As for me personally, I got it to compile using Eclipse, but as soon as GM hooks into the DLL, it just quits. No errors or anything, not in the compiler nor in GM, so I have no idea if the problem is the way Eclipse compiled it or something in the code.

So I'd suggest someone who knows for a fact their compiler works should compile it and see if this DLL works.

-IMP

*EDIT* It's definitely the compiler causing the problems. I made a simple DLL that just returns the string "Good" and that crashed GM the same way. Eclipse is apparently screwing something up.

Edited by IceMetalPunk, 15 September 2011 - 06:20 PM.

  • 0

#13 SyncViews

SyncViews

    GMC Member

  • GMC Member
  • 392 posts

Posted 15 September 2011 - 07:05 PM

Your running into undefined behaviour there with the string return and are lucky that ever works. Your string object is being destroyed before GM gets it, and so GM is left with a pointer to invalid memory.

Also check CreateDC didn't fail, check that GetPixel is supported by the device, and you need to do bounds checking on the x and y coordinate.

The GetPixel docs seem to imply it doesnt do the extensive checking other API's do, and that it will fail in some undefined way as opposed to indicate failure and let you call GetLastError.


Also make sure the dll and GM calling conventions line up (you didnt define one there. the default is usually __cdecl but can be changed and I dont think C++ actually defines it). Messing up the stack will generally crash things :)

Edited by SyncViews, 15 September 2011 - 07:11 PM.

  • 0

#14 storkEXEC

storkEXEC

    GMC Member

  • New Member
  • 365 posts
  • Version:GM8

Posted 15 September 2011 - 08:41 PM

it says "string undeclared", i included string.h so i guess it doesn't like me either. :whistle:

EDIT: added using namespace std now I have conversion errors, converting int from double

EDIT: Fixed that but getting conversion errors on this part
str+=itoa((double)c, 10)+" ";

EDIT: Fixed that but at return str.c_str(); I get
invalid conversion from `const char*' to `char*'

EDIT: Fixed that but getting
[Linker error] undefined reference to `CreateDCA@16'
[Linker error] undefined reference to `DeleteDC@4'
after compile

EDIT: Fixed that but get crap results after using in GM

returns a string of dM dL d d@d

Here is the DLL C++ code:

#define GMString extern "C" __declspec(dllexport) char*
#include <string>
#include <stdlib.h>
#include <windows.h>
using namespace std;

GMString getPixels(double x, double y, double w, double h) {
COLORREF c;
HDC hDC;
hDC = GetDC(NULL);
string stri;
char temp1[0];
string stri2;


int x2 = int (x);
int y2 = int (y);
int w2 = int (w);
int h2 = int (h);

for (int xx=x2; xx<x+w2; xx++) {
for (int yy=y2; yy<y+h2; yy++) {
c=GetPixel(hDC, xx, yy);
itoa(c, temp1, 10);
stri = temp1[0]+" ";
}
}

ReleaseDC(GetDesktopWindow(), hDC);


return const_cast<char *>(stri.c_str());
}

Here is the GM code:

global.dll_getpixel = external_define("getpixelbeta.dll", "getPixels", dll_cdecl, ty_string, 4, ty_real, ty_real, ty_real, ty_real);


Edited by storkEXEC, 16 September 2011 - 12:05 AM.

  • 0

#15 IceMetalPunk

IceMetalPunk

    InfiniteIMPerfection

  • Retired Staff
  • 9259 posts
  • Version:Unknown

Posted 15 September 2011 - 10:30 PM

Your running into undefined behaviour there with the string return and are lucky that ever works. Your string object is being destroyed before GM gets it, and so GM is left with a pointer to invalid memory.

Heh, I actually originally had it use strcpy() to copy the data over to a C-string and return that, but I didn't think it was necessary. If it is, I can always add it back, but I think we should focus on getting it to compile at all first :lol: .

Also check CreateDC didn't fail, check that GetPixel is supported by the device, and you need to do bounds checking on the x and y coordinate.

Yes, there's some error checking I need to do, but I always get the fundamentals working first (assuming all input will be correct) before moving on to the details.

The GetPixel docs seem to imply it doesn't do the extensive checking other API's do, and that it will fail in some undefined way as opposed to indicate failure and let you call GetLastError.

Right. Which will be annoying when I get to error checking, but for now, it's irrelevant.

Also make sure the dll and GM calling conventions line up (you didnt define one there. the default is usually __cdecl but can be changed and I dont think C++ actually defines it). Messing up the stack will generally crash things :)

This I don't understand. If you're talking about the __declspec, I already have that... Sorry if I sound stupid here, but I don't have a ton of experience in C++, just a little bit (2.5 semesters of school for it and a tiny bit of personal use).

-IMP

*EDIT* @storkEXEC: Yeah, those are the errors Dev-C++ was throwing at me. Not the const char* to char* one, though. I have an idea to fix that (which would be returning to the original code I had written, and what SyncViews pointed out). Instead of returning str.c_str(), try doing this (right after DeleteDC()):

char ret[str.length()+1];
strcpy(ret, str.c_str());
return ret;

That might help.

Edited by IceMetalPunk, 15 September 2011 - 10:33 PM.

  • 0

#16 storkEXEC

storkEXEC

    GMC Member

  • New Member
  • 365 posts
  • Version:GM8

Posted 16 September 2011 - 12:09 AM


Your running into undefined behaviour there with the string return and are lucky that ever works. Your string object is being destroyed before GM gets it, and so GM is left with a pointer to invalid memory.

Heh, I actually originally had it use strcpy() to copy the data over to a C-string and return that, but I didn't think it was necessary. If it is, I can always add it back, but I think we should focus on getting it to compile at all first :lol: .

Also check CreateDC didn't fail, check that GetPixel is supported by the device, and you need to do bounds checking on the x and y coordinate.

Yes, there's some error checking I need to do, but I always get the fundamentals working first (assuming all input will be correct) before moving on to the details.

The GetPixel docs seem to imply it doesn't do the extensive checking other API's do, and that it will fail in some undefined way as opposed to indicate failure and let you call GetLastError.

Right. Which will be annoying when I get to error checking, but for now, it's irrelevant.

Also make sure the dll and GM calling conventions line up (you didnt define one there. the default is usually __cdecl but can be changed and I dont think C++ actually defines it). Messing up the stack will generally crash things :)

This I don't understand. If you're talking about the __declspec, I already have that... Sorry if I sound stupid here, but I don't have a ton of experience in C++, just a little bit (2.5 semesters of school for it and a tiny bit of personal use).

-IMP

*EDIT* @storkEXEC: Yeah, those are the errors Dev-C++ was throwing at me. Not the const char* to char* one, though. I have an idea to fix that (which would be returning to the original code I had written, and what SyncViews pointed out). Instead of returning str.c_str(), try doing this (right after DeleteDC()):

char ret[str.length()+1];
strcpy(ret, str.c_str());
return ret;

That might help.


Okay the DLL works if I replace
stri=temp1[0]+" ";
with
stri="abd";

so the problem may lie in the HDC or in the temp1 array.
  • 0

#17 SyncViews

SyncViews

    GMC Member

  • GMC Member
  • 392 posts

Posted 16 September 2011 - 12:11 AM

So now your returning a pointer to the stack that gets invalidated, and will fail if GM users more stack space before it copies that string. To safely return a string it must be located some where that doesnt get invalidated by the return (e.g. a string literal, static var or global).

Oh and dynamically sized stack arrays are not in the C++ standard, thats a C99 feature (another case where "C++ is a superset of C" is wrong). Many compilers wont accept that syntax (you can do it yourself with somthing like alloca but thats fairly advanced stuff, but still wont solve the string invalidation issue).


Heh, I actually originally had it use strcpy() to copy the data over to a C-string and return that, but I didn't think it was necessary. If it is, I can always add it back, but I think we should focus on getting it to compile at all first :lol: .

Sorry I took your post as you got it to compile on the compilers you have with some settings, but the DLL was crashing GM, hence the list of things you can do to cause a crash :)

This I don't understand. If you're talking about the __declspec, I already have that... Sorry if I sound stupid here, but I don't have a ton of experience in C++, just a little bit (2.5 semesters of school for it and a tiny bit of personal use).

It is not a C++ detail as such, but more a fundamental one about how the CPU works. The CPU has a bunch of registers, as well as the computers main memory, a portion of which is used as the stack. Data is added and removed from the top of the stack.

The calling convention defines how a function is called, since it turns out there are many ways to use the stack and available registers to pass parameters and get return values, as well as if the caller or callee should clean up the stack, and which registers to use for various purposes.

GameMaker supports the stdcall and cdecl calling conventions for extension DLL's. Both pass all their parameters on the stack in right to left order (so for the function f(a,b,c) the machine code pushes the values of c, b and a onto the stack in that order), use the EAX register for the return value, and additonally define the ECX and EDX registers for the functions use (the other data registers must be preserved, that is they must hold the same value after the function as they did at the start). The difference between these two is that in stdcall the callee cleans up the stack (POP's the parameters from it) and with cdecl the caller cleans it up. The result is that if the caller and callee use different conventions, you may corrupt the stack by either cleaning it twice, or not at all.

There are also a number of other calling conventions.

Edited by SyncViews, 16 September 2011 - 12:15 AM.

  • 0

#18 IceMetalPunk

IceMetalPunk

    InfiniteIMPerfection

  • Retired Staff
  • 9259 posts
  • Version:Unknown

Posted 16 September 2011 - 12:21 AM

So now your returning a pointer to the stack that gets invalidated, and will fail if GM users more stack space before it copies that string. To safely return a string it must be located some where that doesnt get invalidated by the return (e.g. a string literal, static var or global).

Oh and dynamically sized stack arrays are not in the C++ standard, thats a C99 feature (another case where "C++ is a superset of C" is wrong). Many compilers wont accept that syntax (you can do it yourself with somthing like alloca but thats fairly advanced stuff, but still wont solve the string invalidation issue).

So...if I were to simply make that string global, it would be fine to return str.c_str()?


Heh, I actually originally had it use strcpy() to copy the data over to a C-string and return that, but I didn't think it was necessary. If it is, I can always add it back, but I think we should focus on getting it to compile at all first :lol: .

Sorry I took your post as you got it to compile on the compilers you have with some settings, but the DLL was crashing GM, hence the list of things you can do to cause a crash :)

Yeah, that is the case. But like I mentioned in the other post, it crashes even if I just return the string literal "Good". No matter what it returns, it crashes GM.


This I don't understand. If you're talking about the __declspec, I already have that... Sorry if I sound stupid here, but I don't have a ton of experience in C++, just a little bit (2.5 semesters of school for it and a tiny bit of personal use).

It is not a C++ detail as such, but more a fundamental one about how the CPU works. The CPU has a bunch of registers, as well as the computers main memory, a portion of which is used as the stack. Data is added and removed from the top of the stack.

The calling convention defines how a function is called, since it turns out there are many ways to use the stack and available registers to pass parameters and get return values, as well as if the caller or callee should clean up the stack, and which registers to use for various purposes.

GameMaker supports the stdcall and cdecl calling conventions for extension DLL's. Both pass all their parameters on the stack in right to left order (so for the function f(a,b,c) the machine code pushes the values of c, b and a onto the stack in that order), use the EAX register for the return value, and additonally define the ECX and EDX registers for the functions use (the other data registers must be preserved, that is they must hold the same value after the function as they did at the start). The difference between these two is that in stdcall the callee cleans up the stack (POP's the parameters from it) and with cdecl the caller cleans it up. The result is that if the caller and callee use different conventions, you may corrupt the stack by either cleaning it twice, or not at all.

There are also a number of other calling conventions.

Yes, I know this. What I meant was that I thought the __declspec(dlleport) part of my GMString definition was signifying the calling convention as cdecl...or have I misunderstood?

-IMP
  • 0

#19 storkEXEC

storkEXEC

    GMC Member

  • New Member
  • 365 posts
  • Version:GM8

Posted 16 September 2011 - 12:28 AM

I got it to work, but it runs at about 25 fps. I assume it's because it constantly opens and closes the HDC.

Here is the code:

#define GMString extern "C" __declspec(dllexport) char*
#include <string>
#include <stdlib.h>
#include <windows.h>
using namespace std;

GMString getPixels(double x, double y, double w, double h) {
COLORREF c;
HDC hDC;
hDC = GetDC(NULL);
string stri;
double size = (w-x)*(h-w);
int size2 = int(size);
char temp1[size2];
string stri2;


int x2 = int (x);
int y2 = int (y);
int w2 = int (w);
int h2 = int (h);
int i = 0;

for (int xx=x2; xx<x+w2; xx++) {
for (int yy=y2; yy<y+h2; yy++) {
c=(GetPixel(hDC, xx, yy));
itoa(c, temp1, 10);
stri += temp1;
stri += " ";
i+=1;
}
}

ReleaseDC(GetDesktopWindow(), hDC);


return const_cast<char *>(stri.c_str());
}

Edited by storkEXEC, 16 September 2011 - 12:30 AM.

  • 0

#20 IceMetalPunk

IceMetalPunk

    InfiniteIMPerfection

  • Retired Staff
  • 9259 posts
  • Version:Unknown

Posted 16 September 2011 - 12:43 AM

Glad you got it working :D .

I suppose you can make the HDC a global variable, then separate the DC opening/closing into their own functions:

#define GMString extern "C" __declspec(dllexport) char*
#define GMReal extern "C" __declspec(dllexport) double
#include <string>
#include <stdlib.h>
#include <windows.h>
using namespace std;

HDC hDC;

GMReal init() {
  hDC = GetDC(NULL);
  return 1;
}

GMString getPixels(double x, double y, double w, double h) {
COLORREF c;
HDC hDC;
string stri;
double size = (w-x)*(h-w);
int size2 = int(size);
char temp1[size2];
string stri2;


int x2 = int (x);
int y2 = int (y);
int w2 = int (w);
int h2 = int (h);
int i = 0;

for (int xx=x2; xx<x+w2; xx++) {
for (int yy=y2; yy<y+h2; yy++) {
c=(GetPixel(hDC, xx, yy));
itoa(c, temp1, 10);
stri += temp1;
stri += " ";
i+=1;
}
}

return const_cast<char *>(stri.c_str());
} 

GMReal cleanup() {
  ReleaseDC(GetDesktopWindow(), hDC);
  return 1;
}

Then just create the GM script-equivalents to call these new functions.

-IMP

Edited by IceMetalPunk, 16 September 2011 - 12:43 AM.

  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users