Copy Link
Add to Bookmark
Report

Xine - issue #5 - Phile 109

eZine's profile picture
Published in 
Xine
 · 7 months ago

 

Ú-----------------------------¿
| Xine - issue #5 - Phile 109 |
À-----------------------------Ù












A little Introduction to the opengl
+-----------------------------------+





Hey pals, I imagine as me you grew with these doom like and opengl
demos, wacthing on your little screen the polygons moving, while launching
rockets and such. Also, you are a dickhead at math and you don't want to
build all these mathematical sinuso‹dal routines. Well, opengl is a cool
library wich permit you to define a 3D universe very easily, to move it and
apply a series of effect with the simple concept of an api.

Today, there's two main opengl coding, depending on wich system you
are, the normal way is using glut library in order of defining the animation,
wich is compatible linux, win32, sgx stations etc etc... the other way is
the pure win32 one. The last one use the win32 client call back in order
to switch to next image. Anyway, the result is the same. But you know on
wich platform we are building these little viruses. So, for using opengl,
you need to init the window proc




1 The Window proc
+----------------------+


the window proc is basically a call back wich handle all system/machine
events attached to the current (displayed or not) window. The principe work
great for GUI and diminuish the amount of eaten machine ressource.





1.1 The window class
+------------------------+

For initialising a window proc, you need to define a class, the class is
a little structure defining various information, but specially the address
of the window procedure. It's very easy to initialise, an api call

mov edx,esp ; save stack

push offset classname
push 0 ; window menu
push 0 ; background color (black)
push 0 ; our cursor
push 0 ; our icon

push edx ; save stack
push 0
call GetModuleHandleA ; load current program
pop edx

push eax ; equal hinstance

push 0 ; suplementary allocated memory
push 0 ; additional size to this struct
push offset Window_proc ; address of the window_proc
push 0 ; we don't care of style

mov eax,esp

push edx
push eax
call RegisterClassA ; register the class
pop esp ; restore the stack

Once you have your little class registered you need to create your own
window procedure.





1.2 Creating the window
+-----------------------+


it's easy, just an api call

push 0

call GetModuleHandleA
push eax

push 0
push 0
push 480
push 640
push 0
push 0
push 090000000h ; WS_VISIBLE
push offset windowname
push offset classname
push 0400000h ; WS_EX_CLIENTEDGE

call CreateWindowExA

This is correct, but if you call that only like that, it may crash, why ?
coz we have not yet created the window proc




1.3 The window proc
+-----------------------+


The window proc is a basic procedure wich receive 4 arguments. The first
argument is the window handle. The second argument is the message. The
third is the low param and the fourth is the high param.

As windows work in a c like environment, argument are dropped on stack. So,
it's easy to access them. Also you need to ret 16. You need also to keep
care of some registers, do not modify ebp as exemple or you will crash.

Your window proc need to intercept some message, message are part of the
win32 constants. let have a look on what look like a window proc.

lParam equ 16
wParam equ 12
uMsg equ 8
hWnd equ 4

window_proc:

cmp dword ptr [esp+uMsg], 0Fh ; WM_PAINT
jne not_event1

... put here WM_PAINT code

not_event1:

... put here other events you want

not_event99:

cmp dword ptr [esp+uMsg], WM_CLOSE
jne not_quiting

push dword ptr [esp+lParam]
push dword ptr [esp+4+wParam]
push dword ptr [esp+4+4+uMsg]
push dword ptr [esp+4+4+4+hWnd]
call DefWindowProc

ret 16




1.4 forking the message
+---------------------------+


For some reason, some message are received and some messages have to be
sent, For this, you need to dedicate the current thread for forking messages,
wich cost a very low ressource in fact. So don't panick. This code is
very generic in fact, it may vary from a programmer to an other, but it's
all the time the same snippet.

mov edx,esp
sub esp,44
mov ebx,esp

push ebx
push eax

loopit:

push ebx

push 0
push 0
push eax
push ebx
call GetMessageA

pop ebx

cmp eax,0
je goodbye

push ebx
push ebx
call TranslateMessage
call DispatchMessageA

pop eax
pop ebx

push ebx
push eax
jmp loopit

goodbye:

program_error:

add esp,44+4+4

push 0
call ExitProcess

Once your window proc initialized, oh joy ! nothing, that's normal, you need
to sync the window proc with the opengl




2 The opengl
+------------------+


Now, as a standard window gui, we have a register class/window, and the
tiny window proc wich will permit us many thing. But now, we need the
help of the opengl in order to init the system, the graphic viewpoint
and a lot things. There's mainly two things to do: at creating, and
when the screen is refreshed. The method described here is only mine,
acquired from various tutorial, documents. Keep a critical view point of
it.




2.1 At window creation time
+--------------------------------+

First of all, you need to initialize the pixel format, this pixel format
handle for use various graphical technique, as a double graphical buffer.
For that, you need the use of a PIXELFORMATDESCRIPTOR, it's a long
structure boring, where only a few information need to be filled. let see

mov ecx,40
sub esp,ecx
mov edi,esp
push edi

xor eax,eax
repz stosb

pop edi

mov word ptr [edi], 40 ; sizeof the structure
mov word ptr [edi+2], 1 ; fill version
mov dword ptr [edi+4], 37 ; PFD_SUPPORT_OPENGL
; PFD_DRAW_TO_WINDOW
; PFD_DOUBLE_BUFFER
mov byte ptr [edi+9], 16 ; color bit
mov byte ptr [edi+17], 16 ; depth bit

push edi
push dword ptr [currentDC] ; load the DC
call ChoosePixelFormat

if the return equal 0, the api failed, and the user can't display the
resolution. Else, you can directly set the pixel format.

push edi
push eax
push dword ptr [currentDC] ; load the DC
call SetPixelFormat

then it's equal the pixel format. To get the CurrentDC, it's very easy:

push dword ptr [esp+hWnd]
call GetDC

and then eax equal the current DC. We also need to create an opengl context
from this DC.

push eax
call wglCreateContext

if eax = 0, then we have failed, and the best to do is to send a wm_close
wich will close in good form the application.

after, we need to synchronize both context

push eax ; opengl contect
push ebx ; currend DC
call wglMakeCurrent

that done, the opengl has been initialized, cool, now you can apply all
a series of effect, but before applying them, you need to enable them.
I let you choose from documents wich one you would like, (but try these
ones: GL_DEPTH_TEST, GL_LIGHTING), active them this way :

push 0B57h ; CL_COLOR_MATERIAL
call glEnable ; damn easy isn't ?







2.2 Once the window is being resized
+-------------------------------------+

when windows has been done the initializing, windows send a WM_SIZE message,
this message mean that it's time to fix all a series of graphical things.
The screen resolution has been sent in lParam. So first, set the viewport

mov ecx,dword ptr [esp+lParam]
movzx edx,cx
shr ecx,16

push ecx
push edx ; lenght
push 0
push 0 ; start
call glViewport ; define viewport

After, we need to define the matrix model, I will not make a math lesson
about matrix and transformations, but as usual, it's very easy

push 1701h ; GL_PROJECTION
call glMatrixMode

after, we take the Indentity matrix wich will make corresponding to X Y Z
the X Y Z coordinate :)

call glLoadIdentity

then, we will call a gl effect library to add perspective to the viewport,
well you could recode it yourself, but it's a bit long and may ask you
some skill you have not, a special api is dedicated but this api accept only
double floating point precision. The compiler can init double via

double1 dq 1.0f

a standard double push is

pushdl macro double1

fld qword ptr [&double1&]
sub esp,8
fstp qword ptr [esp]

endm

if you macroize that, you can then pass to the viewport.

pushdl farclip
pushdl nearclip
pushdl XYration
pushdl FovAngle

call gluPerpective

The perspective will give us a nicest aspect to our 3D world. Set it
as you like, you can give a camera like vision or an alien extended or
a 16/9 vision of the scene.

And optionnaly, you can set the shade model, for complex 3D, set it to
GL_FLAT, it may speed up previewving of gouraud or other heavy image
rendering.

push 01D01h
call glShadeModel

and that's all for now.






3 It's time for your democoder skills
+-------------------------------------------+

Windows tell the window proc that it's time to refresh the current image
via the WM_PAINT message.

The very first thing to do is to clear a few variables

push 04100h ; GL_COLOR_BUFFER_BIT or
call glClear ; GL_DEPTH_BUFFER_BIT

push GL_MODEL_VIEW
call glMatrixMode

call glLoadIdentity

now, it's clear for use and we can set the viewport, it's like a camera.
This camera have 9 operands.

The 3 first are the start of the camera
The 3 after are the destination of the camera
The 3 last are the coordinate of the up vector of the camera,
the rotation of it.

these operand are double again, then use pushdl in order to use it.

pushf...
pushf...
call gluLookAt

Now, it's time for you to draw the environment, you can do many things,
set lingths, shadow, transparency, distorsion, etc etc...

let's see an easy thing:

push GL_POINTS
call glBegin

push 0.5
push 0.5
push 0.5
call glVertex3f

call glEnd

glColor3d and glVertex3i exist under many format, in fact, the last
letter design wich type of variable you want to use. glVertex3d mean
you use double as argument, capisco

when the environment is build, you can finish by:

push DC
call SwapBuffers

and the swapped buffer will be flushed to screen.






4 Little Appendix
+-----------------------+

Often, ppl wonder why their production appears strange on screen, the
reason is simple, opengl dont take care of other elements if they exist,
so, it may overwrite them on screen, boring isn't ? You can set a depth
test at creation time

push 0B71h ; DEPTH_TEST
call glEnable ;

Some ppl would like to have a full screen resolution, this can be done
in two steps, fix the display setting:

mov ecx,148
mov esp,ecx
mov edi,esp
xor eax,eax

repz stosb

mov dword ptr [esp+36],148 ; dmSize
mov dword ptr [esp+104],16 ; dmBitsPerPixel
mov dword ptr [esp+108],640 ; dmWidth
mov dword ptr [esp+112], 480 ; dmHeight
mov dword ptr [esp+40], 1C0000h
; DM_BITSPERPEL DM_PELSWIDTH DM_PELSHEIGHT

mov edx,esp

push 4 ; CDS_FULLSCREEN
push edx ; dmScreenSettings
call ChangeDisplay

add esp,148

it's easy as bonjour isn't ?


← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT