News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Using OpenGL functions with the opengl32.inc and opengl32.lib files

Started by hamper, October 23, 2013, 05:13:35 AM

Previous topic - Next topic

hamper

glColor3ui PROTO STDCALL :DWORD,:DWORD,:DWORD

As I understand it, if I use the function glColor3ui, which takes three dword arguments, the largest integer value I can specify (4294967295) is automatically mapped to 1.0, and 0 maps to 0.0. Values in between are linearly mapped to the nearest corresponding floating point value. That's fine, and it's all covered that way in the OpenGL reference information (and by Microsoft). So in this case the prototype and the function tie together.

But there are many examples where they do not tie together...

The function wglSetPixelFormat should, according to the OpenGL reference information, have a pixel format index argument that is an int, i.e. an sdword in assembly language. However, the prototype in opengl32.inc is:

wglSetPixelFormat PROTO STDCALL :DWORD,:DWORD,:DWORD

So can I just "re-prototype" the function as :dword,:sdword,:dword and use an sdword instead, as it's supposed to be? What's the library opengl32.lib actually expecting the data type of this argument to be? And will it complain/fail if I try to use an sdword instead of a dword?

For the wglSetPixelFormat function it 'might' not be a problem, using an unsigned value where a signed value should be used, if the pixel format index itself is always a positive integer value. But as yet I don't know whether or not this would always be the case.

Here's an example that could be very problematical though, I suspect:

According to the OpenGL reference information, these two functions (for example) should have the argument types stated:

glVertex2i      GLint        i.e. sdword
glVertex2s      GLshort      i.e. sword

But the prototypes in opengl32.inc are actually as follows:

glVertex2i PROTO STDCALL :DWORD,:DWORD
glVertex2s PROTO STDCALL :DWORD,:DWORD

So if I stick with using dword arguments, and specify an x value as 4294967295, does that automatically map to a floating point value? If so, what value? And what unsigned integer values do I have to use in order for them to get mapped to negative floating point coordinates?
Alternatively, if I "re-prototype" using sdword and sword arguments, will the library complain? I.e. what is the library actually expecting these arguments to be? Or will the values just get accepted and mapped, say, -32768 to -1.0, and 32767 to +1.0? Is automatic mapping integer-to-floating point even supported for these functions?

In fact, just about every OpenGL function seems to be prototyped as a dword in opengl32.inc - even functions that should be taking floating point arguments. I assume there must be some logic behind this, but I'm at a loss to figure out what it is. It certainly doesn't seem to tie up with the OpenGL reference information on functions and the type of arguments they are expecting to receive.

I realise that I could just use floating point values, but I find integers easier to work with. And I'd still come up against the same problem - a prototype specifying dword values when the function is written around the use of floating point values.

Can anyone shed any light on this?

Thanks in anticipation.

qWord

For MASM it sufficient if the size of the types match, thus there is no difference in using DWORD,SDWORD or REAL4. MASM only requires correct types for structures and unions (a typecast could solve that).

For (S)WORD and (S)BYTE the problem is that the invoke-macro in earlier versions of MASM produce bad code for such parameters. However, it is unproblematic to use (S)DWORDs instead, because parameters size is round up to 4 bytes to not break the stack alignment. For the passed values it must only be ensured that they do not exceed the type range - the function only use the low WORD/BYTE. Negative values are also no problem because of the two's complement.

BTW: STDCALL only use the parameter size in bytes - there is no type information in the name decoration. e.g. _MessageBoxA@16 => 4 DWORD arguments.
MREAL macros - when you need floating point arithmetic while assembling!

hamper

Thanks qWord,

So are you saying that I could use dword, sdword or real4 arguments as I see fit, with exactly the same function call, and the library will automatically work out what to do based on the data types of the arguments I have supplied? How does the library work that out? I thought the whole idea of using a prototype was so that the assembler could check that the arguments passed are of the correct data type.

But if you say it doesn't matter, so long as the data sizes are correct, then why not, for example, prototype glVertex3f as taking three real4 arguments instead of the three dword arguments that are actually in opengl32.inc? Why not do the job properly in the first place and avoid all the confusion?

I don't understand what you're saying about "the function only use the low WORD/BYTE. Negative values are also no problem because of the two's complement". If the function only uses the low word of a dword argument, then how does it know what the true value is, and whether it's a positive unsigned or a negative signed value, because in 2's complement it is the HO bit that's critical, so only using the LO word or byte ignores the sign bit?


qWord

Quote from: hamper on October 23, 2013, 08:38:14 AMthe library will automatically work out what to do based on the data types of the arguments I have supplied? How does the library work that out?
the import library does not work out anything - the linker search the unresolved symbols (in this case a function) of the assembler generated object file in the import library. Only the names matter (see name mangling/decoration, STDCALL, C). The programmer choose the correct function, which has fixed types. You may read up about calling convention in this context - Anger Fog has a good manual about that.

Quote from: hamper on October 23, 2013, 08:38:14 AMI thought the whole idea of using a prototype was so that the assembler could check that the arguments passed are of the correct data type.
the type cheking is limited (its an assembler!). The main purpose of the macro is probably to produce compact and readable code whereas avoiding invalid parameter size and count.

Quote from: hamper on October 23, 2013, 08:38:14 AMBut if you say it doesn't matter, so long as the data sizes are correct, then why not, for example, prototype glVertex3f as taking three real4 arguments instead of the three dword arguments that are actually in opengl32.inc? Why not do the job properly in the first place and avoid all the confusion?
good question - I'm also a fan of correctly typed prototypes and PROCs (except for functions where the parameter passing can be simplified)

Quote from: hamper on October 23, 2013, 08:38:14 AMIf the function only uses the low word of a dword argument, then how does it know what the true value is, and whether it's a positive unsigned or a negative signed value
as said above, the functions types are fixed: if you call a function that expects a REAL4, then you must past a float value.
For the integers, see how the two's complement is encoded.
MREAL macros - when you need floating point arithmetic while assembling!

hamper

Thanks again qWord,

So, if I'm understanding you correctly, I can pass sword values to glVertex3s, sdword values to glVertex3i, and real4 values to glVertex3f, even though they are all prototyped with dword arguments, and the linker will search for the correct function name - glVertex3s, glVertex3i or glVertex3f - and use the code for that, which is therefore written around using a particular data type for its arguments. Is that right?

And if that is correct, it follows that I can simply "re-prototype" these misleading ones...

glVertex3s PROTO STDCALL :DWORD,:DWORD,:DWORD
glVertex3i PROTO STDCALL :DWORD,:DWORD,:DWORD
glVertex3f PROTO STDCALL :DWORD,:DWORD,:DWORD

...into the forms that they should have had to begin with...

glVertex3s PROTO STDCALL :SWORD,:SWORD,:SWORD
glVertex3i PROTO STDCALL :SDWORD,:SDWORD,:SDWORD
glVertex3f PROTO STDCALL :REAL4,:REAL4,:REAL4

Is that correct as well?


Regards

qWord

Quote from: hamper on October 23, 2013, 07:08:58 PMSo, if I'm understanding you correctly, I can pass sword values to glVertex3s, sdword values to glVertex3i, and real4 values to glVertex3f, even though they are all prototyped with dword arguments
yes, I forgot to mention that MASM will convert arguments, which are smaller than the needed type (if possible). For example, if the parameter is declared as a DWORD and you pass a WORD variable/register, MASM will zero extend the parameter to 32 bit (sign extension is done if the passed argument is a signed type: e.g. invoke,...,SWORD ptr ax). However, this is only practicable with MASM version 9+ (or better JWasm), because earlier versions produce wrong code in some cases - for those you should always pass DWORD sized variables and registers to get correct code.
Quote from: hamper on October 23, 2013, 07:08:58 PMthe linker will search for the correct function name - glVertex3s, glVertex3i or glVertex3f - and use the code for that, which is therefore written around using a particular data type for its arguments. Is that right?
Actual, the OGL function are placed in a system DLL and the import library only associate a specific function with that DLL (which means the DLL contains the function code).
The assembler will generate the whole code for the call according to the prototype declaration, but because the address is not know at the moment of assembling, the final CALL address (=DWORD) is undefined and set to some value (0). In this case the assembler adds a "EXTERNAL" entry to the object file (*.obj), which contains the (mangled) function name and the location of the immediate operand of the CALL instruction (more detailed, the location is added as a "COFF relocation").

The linker see such entries and search for the corresponding counterpart in other modules (=object files), static libraries (= collection of object files) and import libraries, if specified.
If the symbol is found in an object file or static library, the address can be resolved while linking - this behaves like as if the function/procedure's code were placed in the current module.
For import libraries, commonly a sequence of JMP instructions is appended to the code section and the unresolved DLL calls are redirected to these jumps (you can see that when following a call in OllyDbg). The jump targets (= pointer to the functions) are filled by the OS when the module (EXE/DLL) is loaded for execution - for this purpose the so called "import address table" exist in the final image, which associate a JMP with a specific function and DLL.
For more details see the PE/COFF specifications by MS, Wikipedia and - of course - the forum search function (also the old board).

Quote from: hamper on October 23, 2013, 07:08:58 PMI can simply "re-prototype" these misleading ones... [...]Is that correct as well?
yes, if "re-prototype" means replacing the prototype. As said above, use MASM 9+ or JWasm in this case.

qWord
MREAL macros - when you need floating point arithmetic while assembling!