Unofficial glmax2d
BlitzMax Forums/BlitzMax Programming/Unofficial glmax2d
| ||
Here is a basic glmax2d. http://www.blitzbasic.com/codearcs/codearcs.php?code=2612 Feel free to make additions - send them to me and i will add them. Or you could request features to be added. |
| ||
Given what you said in your code archive comments, it looks like the only thing you added was a) ability to define an irregular quad image, and b) ability to add a gradient to drawtext? Not to mock it or anything but with nothing much else `new` why would people want to use it? |
| ||
there are features that people want in max2d that are not being implemented, With this simple version of glmax2d people can request features (in this thread) and they can be put in as long as OpenGL supports those features. Not only features but optimizations. |
| ||
A few features I'd love to see in GLMax2d : - Batch Rendering, I didn't read anything on this yet. - Native functions to draw animated and textured polygons (concave and convex). - SetViewport() replacement since I read everywhere it causes problems on old GFX cards. - More color blending mode (like the one you can use in the Gimp for example). - Fixed rate logic and basic Tweening modules. - Built-in bezier curve and advanced rendering commands (like in Cairo Brucey module). - Easy shaders support but I probably dream on this one ;) OTH |
| ||
Ahh so you want some ideas? Ok. - Unfilled circle/box drawing - Use of vertex arrays to render lots of images/quads/irregular quads, also to do lines and single pixels - ie so that you can draw lots of particles efficiently. - More blend modes - GL does let you do more stuff even in 1.1 - Stencil buffer commands - Textured polygons - Faster circle/ellipse than one that call trig functions (see my code archives for integer solutions) - Grab to texture (glCopyTexSubImage2D()) and use it for drawimage - Store multiple sprites on a single image and draw individual sprites using proper texture coordinates - coupled with your individually positionable vertices - Define vertex color per vertex - lets you create gouraud shading easily - A basic tile engine? |
| ||
batch rendering - what kind of opengl feature do you mean? In OpenGL you have display lists to draw polygons faster theres vertex buffer objects theres also putting several textures on the same texture which do you mean? -textured polygons I think Indiepath has a textured polygon module which I can implement, -animated polygons you can use the setimagevertices commands to animate the vertices -setviewport replacement is there an opengl command better than glviewport? how about the glscissor commands? -color blending modes will look into it -fixed rate logic hasnt got anything to do with opengl really, -bezier curve I dont know if there are any examples of this in the code archives, I shall take a look later -shaders I dont own any graphics cards that can do shaders sorry If anyone else has any ideas how to implement these functions please chime in |
| ||
- Unfilled circle/box drawing yes, should be easy, I had the code to do this - Use of vertex arrays to render lots of images/quads/irregular quads, also to do lines and single pixels - ie so that you can draw lots of particles efficiently. yes should be okay which opengl command does this? VBO's? display list's? - More blend modes - GL does let you do more stuff even in 1.1 yep should be okay - Stencil buffer commands might need some help here, I had a look at some stencil buffer documentation = couldnt make head nor tail of it. - Textured polygons yep, Indiepath has already done it, integrating it shouldnt be a problem - Faster circle/ellipse than one that call trig functions (see my code archives for integer solutions) ok, if you have already done the code yourself, should be quick to implement - Grab to texture (glCopyTexSubImage2D()) and use it for drawimage interesting, what are the advantages out of curiosity? - Store multiple sprites on a single image and draw individual sprites using proper texture coordinates - coupled with your individually positionable vertices yes, should be easy - Define vertex color per vertex - lets you create gouraud shading easily yes should be easy - A basic tile engine? hmm possibly, seems like it could be out of scope of this project, I think most people like to use their own? |
| ||
From what I understand, SetViewPort() works in OpenGL. It is the DirectX version that does not work. |
| ||
This "basic tile engine" thing sounds pretty sarcastic imo. Nice there's finally an easy public max2d module option to build upon, thank you. |
| ||
TaskMaster - well theres definetly no plans for a directx version so thats not a problem :) beanage - you're welcome, please share if you make some cool additions |
| ||
missed the payback. Ha...Ha...Ha... |
| ||
lol how about I translate my fist to your face? j/k |
| ||
By basic tile engine I just mean a) have some simple data structure into which you can assign sub-image p to tile at tile coords x,y, then call like `draw map` to draw it, or something simple like that. Even a very simple tilemap system would help beginners especially to make quick progress. The stencil buffer can be a bit complicated and the way it's set up in OpenGL is sort of not very straightforward. As you draw something to the screen, you can have the stencil buffer test for the presence of a `set bit` in the stencil, and then decide whether to allow that particular pixel to be drawn. At the same time as testing existing stencil bits, you can write to the stencil those pixels which gets past the stencil test. So it's kind of like you do a read from the stencil, test with it, then optionally also write to the stencil. But setting it up is not very easy to grasp - reference values and stencil functions and all that. To help you out, I am providing below my current stencil-buffer code. You can use it freely for whatever you like. Blitz on the Amiga had stencils and they could be quite useful. There is a lot you can use them for. You can draw whatever shape you like as a stencil, made up of as many drawing commands as you like, and then that area can be protected from or stencil-in future drawing operations, letting you easily draw behind stuff, etc. After a LOT of consideration of the functionality provided by the stencil buffer I came up with these functions which I hope/think captures everything you'd want to do. I refer to the ability to write to the stencil as `stencil recording` which you set up with GStencilRecord(). The `threshold` and the write and read `masks` work together to let you select/work with/write to/read from any set of bits in the stencil buffer. On most systems the stencil buffer is usually an 8-bit byte buffer (one byte per pixel), but for ease you can just write $FF to set and test a pixel). I refer to the ability to `test the stencil` and fail/pass pixels, as `stencilling` which can be enabled or disabled with GStencilling(). You also might want the GOutput() function, which lets you switch off writes to the color buffer - sometimes you want to draw stuff to the stencil buffer without wasting time drawing the actual pixels in color. Even without drawing in color, pixels can still be calculated and recorded/tested in the stencil. Also I use something I set up called `multi begin` and `multi end` which basically is just an attempt to keep track of whether I would have used a glBegin() glEnd() and for which type of geometry. If you then do a graphics op like draw more quads and you already just drew some quads, you wouldn't need to start glBegin() again so that's just one way to manage it. So you can see references to that in the code - you can take it out or recode it. It helps speed things up a bit in some immediate mode operations. Note that I pass normal OpenGL constants for some parameters, you may want to make your own more friendly/easy-to-remember constants. Note also I included GClearStencil() which you'll need to call at least once before you use the stencil buffer, and optionally each frame. You can, however, set the stencil to clear to 0 the bits you have tested, which is like clearing as you go and is more efficient. Note also in GStencilRecord it refers to 3 operations, which relate to the results of the depth test (if enabled - which it normally is not). See GL documentation for how to use, but generally the third of the three is the most useful. GL_REPLACE just means it will replace the contents of the stencil buffer if the zbuffer test was okay (or switched off). You can use others like GL_ZERO to clear it after testing. You can also define how the testing is performed, like if a value is greater than, equal, less than or equal, notequal, etc versus the threshold value, combined with masking. It does get complicated. 'GL stencil testing modes Global GStencil:Int=False 'Whether to stencil/mask drawn pixels using the stencil buffer content Global GStenMode:Int=GL_ALWAYS 'What GL mode To test the stencil with To determine whether To draw pixels Global GStenThreshold:Int=0 'The stencil test reference value Global GStenReadMask:Int=$FFFFFFFF 'A mask AND'ed with the threshold value and stencil-buffer-pixel when doing a test, to test against specific bits Global GStenWriteMask:Int=$FFFFFFFF 'A mask AND'ed with the stencil pixel being written to write only to specific bits Global GStenRecord:Int=False 'Whether to record new stencil content using incoming fragments Global GStenRecordFailMode:Int=GL_REPLACE 'What GL mode to record stencil data to the stencil buffer when the stencil test fails Global GStenRecordZFailMode:Int=GL_REPLACE 'What GL mode to record stencil data to the stencil buffer when the Z-buffer test fails but the stencil test passes Global GStenRecordZPassMode:Int=GL_REPLACE 'What GL mode to record stencil data to the stencil buffer when the stencil test passes and the depth test fails (or is not used) Function GStencilRecord(DoRecording:Int=False,FailMode:Int=GL_REPLACE,ZFailMode:Int=GL_REPLACE,ZPassMode:Int=GL_REPLACE) 'Set whether to record new drawn geometry into the stencil, and in what mode based on the result of stencil and depth tests 'Allowed: GL_KEEP, GL_ZERO, GL_REPLACE, GL_INCR, GL_DECR, and GL_INVERT 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Switch stencil recording on or off and set its mode If DoRecording=True glStencilMask(GStenWriteMask) 'Set it glStencilFunc(GStenMode,GStenThreshold,GStenReadMask) 'Define the test function glStencilOp(FailMode,ZFailMode,ZPassMode) 'Define the recording operation glEnable(GL_STENCIL_TEST) 'Switch on testing so that the record works, even if testing is GL_ALWAYS GStenRecordFailMode=FailMode 'Store mode GStenRecordZFailMode=ZFailMode 'Store mode GStenRecordZPassMode=ZPassMode 'Store mode GStenRecord=True 'Recording Return Else glStencilMask(GStenWriteMask) 'Set it glStencilFunc(GStenMode,GStenThreshold,GStenReadMask) 'Define the test function glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP) 'Define the recording operation If GStenMode=GL_ALWAYS Then glDisable(GL_STENCIL_TEST) 'Switch off stencilling if not required GStenRecordFailMode=GL_KEEP 'Store mode (if you switch stencil record off, recording mode resets) GStenRecordZFailMode=GL_KEEP GStenRecordZPassMode=GL_KEEP GStenRecord=False 'No recording Return EndIf End Function Function GStencilling(DoStencilling:Int=False,Mode:Int=GL_ALWAYS) 'Change whether to use the stencil to restrict drawing, and in what mode 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Switch stencilling on or off and set the mode If DoStencilling=True glStencilMask(GStenWriteMask) 'Set it glStencilFunc(Mode,GStenThreshold,GStenReadMask) 'Set it glStencilOp(GStenRecordFailMode,GStenRecordZFailMode,GStenRecordZPassMode) 'Set the stencil op glEnable(GL_STENCIL_TEST) 'Enable testing GStenMode=Mode 'Store the mode GStencil=True 'Store state Return Else glStencilMask(GStenWriteMask) 'Set it glStencilFunc(Mode,GStenThreshold,GStenReadMask) 'Set it glStencilOp(GStenRecordFailMode,GStenRecordZFailMode,GStenRecordZPassMode) 'Set the stencil op If GStenRecordFailMode=GL_KEEP And GStenRecordZFailMode=GL_KEEP And GStenRecordZPassMode=GL_KEEP Then glDisable(GL_STENCIL_TEST) 'Disable testing if not required GStenMode=Mode 'Store the mode GStencil=False 'Store state Return EndIf End Function Function GStencilThreshold(Threshold:Int=0) 'Set the stencil compare value - the value from the stencil at which pixels are allowed to be drawn 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Set the threshold glStencilFunc(GStenMode,Threshold,GStenReadMask) 'Set it GStenThreshold=Threshold 'Store the threshold End Function Function GStencilWriteMask(Mask:Int=$FFFFFFFF) 'Change the bit-mask used in stencil testing to confine which bits are writeable 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Set the mask glStencilMask(Mask) 'Set it GStenWriteMask=Mask 'Store the mask End Function Function GStencilReadMask(Mask:Int=$FFFFFFFF) 'Change the bit-mask used in stencil testing to confine which bits are readable during testing 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Set the mask GStenReadMask=Mask 'Store the mask glStencilFunc(GStenMode,GStenThreshold,GStenReadMask) 'Set it End Function Function GClearStencil(Value:Int=0) 'Clear the stencil buffer to a given value 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Clear it glClearStencil(Value) 'Set the clear value glClear(GL_STENCIL_BUFFER_BIT) 'Clear the stencil buffer End Function Function GOutput(AllowRed:Int=GL_FALSE,AllowGreen:Int=GL_FALSE,AllowBlue:Int=GL_FALSE,AllowAlpha:Int=GL_FALSE) 'Define which of the color-buffers channels are enabled for writing output 'Allowed GL_TRUE or GL_FALSE as parameters 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Define output channels glColorMask(AllowRed,AllowGreen,AllowBlue,AllowAlpha) 'Set it End Function Function GMultiBegin(Shape:Int=GL_QUADS) 'Handle multiple calls to glBegin of the same or differnt geometry type 'If we're already inside a glBegin of a particular type, another glBegin 'will not be issued if Shape is the same. When Shape changes to a different 'type of geometry, we glEnd() the current type and start a new glBegin type. 'Be aware that only certain OpenGL commands are allowed inside a glBegin-glEnd 'pair, so make sure to GMultiEnd() before issuing those commands. 'Note that using GMultiBegin without GMultiEnd, geometry may not be drawn 'until a GMultiEnd is called (like a flush command). You can make multiple calls to 'GMultiBegin() without calling GMultiEnd() until later when you are sure you want to flush 'Begin? If GBegun=-1 'Begin a new shape glBegin(Shape) 'Begin a new shape GBegun=Shape 'We have begun this shape, need a glEnd() to follow Return Else 'Begun already, begin a different shape? If GBegun<>Shape glEnd() glBegin(Shape) 'Begin a new, different shape GBegun=Shape 'We are beginning a new shape, need a glEnd() to follow EndIf Return EndIf End Function Function GMultiEnd() 'To finish a block started with MultiBegin() 'This is a substitute for glEnd() which takes into account the state of GMultiBegin 'GMultiBegin will automatically insert a glEnd() if changing geometry type, 'but if you need to end a geometry definition and start using commands which are 'not allowed inside a glBegin/glEnd block, you need to issue a GMultiEnd. 'Note that if geometry is being defined open-endedly by not calling GMultiEnd 'very often, geometry may not be drawn until GMultiEnd is called to complete it. 'but you can make multiple calls to GMultiBegin() and only call GmultiEnd() when 'you want to use commands which don't work in a glBegin-glEnd block. GMultiBegin will 'automatically call glEnd() if changing geometry type. 'End? If GBegun<>-1 glEnd() 'End the geometry GBegun=-1 'Ended all glBegins EndIf End Function I recommend looking at vertex arrays initially for your further batching of rendering calls. It can be 2 or more times faster to render. Display lists are groovy but are becoming a bit depeciated. Often a vertex array is just as fast or nearly so. A vertex buffer object is like storing a vertex array in video ram rather than passing it across the bus, which if the array content doesn't change much could be a lot faster - like maybe for a color array and texture coord array which may not change as much as vertices. You should also try to implement having multiple images on a single image and drawing those sub images individually. You should then try to make as few texture selections as possible. Ie choose a texture, render as many sprites from it as you can, then switch to another texture. Texture swaps slow thing down. If you can put particles on a single texture and render an entire particle engine effect it'll be much quicker that way. glCopyTexSubImage() is the quickest and most backwards compatible way to copy a rectangle from the backbuffer into a texture. You don't have to copy the whole screen. It's fast enough that on most systems you can draw a screen full of graphics, grab it, then re-draw it in some interesting way - perhaps warp it with a mesh, or use it to preserve graphics between frames, or to do feedback effects, etc. |
| ||
From what I understand, SetViewPort() works in OpenGL. It is the DirectX version that does not work. Humm good news then :) -fixed rate logic hasnt got anything to do with opengl really, Well sorry... At first I though it was about a new Max2d module and since the Graphics command and Flip do have a software vsync. About the rest, ImaginaryHuman explained everything in a much better ways ;) |
| ||
SetViewport works because if the viewport is smaller than the whole screen it a) sets a viewport and b) switches on the scissor test. `Scissoring` basically sets up four clipping planes, defining a rectangle, and then when scissor testing is switched on it tests each pixel to see if it is inside the rectangle. If so, it gets drawn. So you should be good to go. I forgot to mention about the stencil buffer, that if you want to do *anything* with stencils you have to make sure to include STENCIL_BUFFER as one of the display flags, either in your graphics driver default flags or pass it to Graphics/GLGraphics. That will create the stencil buffer. You can check if the buffer exists by asking OpenGL with glGetIntegerv ... something about `stencil bits`. If >0 you're good to go. |
| ||
heres my grabimage function:Function GrabImage:TImage(x,y,width,height) Local i:TImage=CreateImage(width,height) glBindTexture GL_TEXTURE_2D,i.num glCopyTexSubImage2D GL_TEXTURE_2D,0,0,0,x,y,width,height Return i End Function Strict Framework keef.gldraw initgl(800,600,0) Local i:TImage Local grabbed=False Local j:TImage=LoadImage("turn arrow.png") While Not KeyDown(key_escape) Cls SetScale(25,25) DrawImage(j,0,0) i=GrabImage(170,50,50,50) If i<>Null SetScale(1,1) DrawImage(i,170,100) EndIf Flip Wend it just draws a white square though instead of what is on the screen |
| ||
i.num is not the texture handle. You have to look at the Frames[0] array element of TIMage, and cast it to something like a TGLImageFrame or something, and then get the `name` field. ie MyTImage.TGLImageFrame(Frames[0]).name |
| ||
in keef.gldraw i.num is the texture handle |
| ||
For some reason the y co-ordinate has to be: GraphicsHeight()-i.height-y the new texture is flipped in the y direction, do I have to create a pixmap and flip it to get it back to normal? |
| ||
your glbegun stuff doesnt make sense if you remove glbegin and glend from the drawrect command and use this program it only draws the first rectangle Framework keef.gldraw initgl(800,600,0) While Not KeyDown(KEY_ESCAPE) Cls glBegin(GL_QUADS) DrawRect 0,0,200,200 DrawRect 200,200,200,200 glend Flip Wend |
| ||
DrawRect calls glBegin and glEnd by itself. You should replace all glBegins with GMultiBegin and all glEnds with GMultiEnd. Right now it looks like you would be nesting them - not allowed. |
| ||
read the post again. I said if you remove glbegin and glend from the drawrect command |
| ||
With all due respect, why would people use this? It could break the nicest feature about bmax, being able to use directx on windows and opengl on other devices. |
| ||
I'd use a good enhanced opengl driver and it sounds like many of the people above would also... if there was an equal dx driver then awesome, but that's not what he's made. with opengl you already get a largely faster driver, 100% of the mac market and 100% of linux and in my sampling, 90% of the windows machines. should be 100's of millions of systems. many of the people here don't sell anything anyway so why would they care if a few old intel embedded systems can't run their stuff. if it's -reasonable- to support both then great but there are many people who write DX only games and alienate all other systems. In any case, who's to say this won't inspire someone to add to the dx driver, nothing's stopping them. |
| ||
Because the problem with Max2D being dual purpose is that its not optimized for either one. It has to work with both DX and OpenGL and that is a limiting factor. In order to add additional functionality it has to be supported in both GL and DX or it can't be added. Its better to IMHO to make a DX version and an OpenGL version so that both can be optimized specific to the technology... and since OpenGL is cross platform it fits better into the Max paradigm and, again IMHO, should be the primarily supported version. |
| ||
Guys, guys, I think you are missing an important point: If To be fair, I would say that at least 60% of all the cards I've ever seen support some form of OpenGL (non-proprietary standards are the BEST!! :D ). Honestly you two went way over my head early in the thread, so I don't want to stop you (it sounds very productive)! |
| ||
The other thing about a multibegin/end is that there are numerous GL commands which you are not allowed to use inbetween a begin/end block. In your DrawRect function (in your code archive), commands like DisableTex gltranslatef(posx,posy,0) glrotatef(rotation,0,0,1) glloadidentity() gltranslatef(0.375,0.375,0) are not allowed to be used within a begin/end section. In my use of multibegin/end you have to do a test for a `begun` state prior to using any disallowed commands, ie end the previous begin if it's still unfinished, then call those commands, then begin anew. That might be what's causing the problem, because it should work otherwise. ie stick a GMultiEnd() before calling those commands. If you want to use the modelview matrix to move/position the images you're drawing, you won't be able to make use of this technique because each quad is going to have to end geometry before it can set up the modelview matrix. Personally I like OpenGL, like many people. I see there is some reason for a benefit to supporting DirectX on Windows - for some people it's a bit faster, for some people slower, for many it's always installed more than GL, but GL isn't far behind. I think if you are going to branch off and make this new Max2D be OpenGL only, that's okay with me and many people, but some people won't like it on Windows. That said there hasn't been any easy to access presence of DirectX library features in BlitzMax - at least GL has some accessibility. Is anyone here writing their own custom DirectX code? I haven't heard of that very much at all. Also I'm not really writing a new Max2D here, I just offered up some useful code and some ideas. I'm working on my own 2D engine so I don't really have any interest in making a second system, I'm just helping your guys out a bit. |
| ||
oh ok then maybe it can be useful for plotting points, thanks for the info |
| ||
todays addition hollow circle and hollow rect |
| ||
"many of the people here don't sell anything anyway so why would they care if a few old intel embedded systems can't run their stuff. " Very true. Good point. |
| ||
i have embedded intel works here |
| ||
it's the older intel... ~3-4+ years. is your's that old? (I'm talking about the age of the drivers here) [edit] and just to be safe... :) my testing wasn't exhaustive but I manage an IT dept that supports 1200 windows machines and 300 macs. the vast majority of the windows machines run intel embedded gfx. we don't keep the gfx drivers up to date so there is quite a mix... I've obviously not tested all those drivers but I ran dx7,dx9 and opengl performance tests on a lot of different computers and most (not all) of the issues were from intel gfx. one very common thing was they would ignore waiting for vblank... that's when I decide I did need to add a timing solution. other problem for very old drivers were solid rects instead of images when using DrawImage. |
| ||
If you want more speed you should look at using vertex arrays, they're not too difficult.. e.g. (textured irregular quads with vertex colors)... Here VertexCoordArray, VertexColorArray and TextureCoordArray are pointers to memory containing arrays of data - you could just use varptr(array[0]) for each instead. Geometry type is your GL_POINTS, GL_LINES, GL_QUADS etc. NumberOfElements is how many objects to draw. You can get 200% speedup using this versus any form of immediate mode glBegin stuff. Here vertices are four sets of 2 floats per quad. Colors are 4 unsigned bytes per vertex. Texture coords are four pairs of 2 floats per quad.glEnableClientState(GL_VERTEX_ARRAY) 'Switch on use of vertex array glEnableClientState(GL_COLOR_ARRAY) 'Switch on use of color array glEnableClientState(GL_TEXTURE_COORD_ARRAY) 'Switch on use of texure coordinate array glVertexPointer(2,GL_FLOAT,0,VertexCoordArray) 'Point to the vertex array glColorPointer(4,GL_UNSIGNED_BYTE,0,VertexColorArray) 'Point to the color array glTexCoordPointer(2,GL_FLOAT,0,TextureCoordArray) 'Point to the texture coordinate array glDrawArrays(GeometryType,0,NumberOfElements) 'Draw the objects! glDisableClientState(GL_VERTEX_ARRAY) 'Switch off use of vertex array glDisableClientState(GL_COLOR_ARRAY) 'Switch off use of color array glDisableClientState(GL_TEXTURE_COORD_ARRAY) 'Switch off use of texture coordinate array |
| ||
looks interesting, if nothing changes between frames I can just call gldrawarrays and the same things will be drawn? if something does change I can just change the blitz array and dont need to point to the arrays again? you cant change the rotation and scale in between quads though? |
| ||
Well... to an extent. When you call glEnableClientState, it activates the use of an array for that particular aspect of data, and disables input from immediate mode for that data. So if you were to leave all three activated, you wouldn't be able to then draw a single quad with glBegin/glEnd inbetween your next use of the arrays. I think. However, if you don't plan to (the user doesn't) draw other stuff and like you say there have been no changes to the data then yes you can just call glDrawArrays and it will re-draw the whole thing without any extra setup. |
| ||
using a vertex array would mean disabling rotation and scale changes in between quads. I like to flip my images with the scale commands. Can you change the binded texture in vertex arrays? todays addition drawshaderect(x,y,width,height,r1,g1,b1,r2,g2,b2,r3,g3,b3,r4,g4,b4) |
| ||
You can only have one texture per call to glDrawArray, so no, you can't change texture as part of the drawing. You are also correct you can't use glRotate and glTranslate on each quad in a vertex array - that's one drawback. You could calculate the rotating/translating yourself and output a second vertex array with modified coordinates, then use that for drawing? It might still be more efficient than not using vertex arrays. |
| ||
todays addition: parent/child images function imageparent(child:Timage,parent:Timage) Function setimagexwhenchild(i:TImage,x) Function setimageywhenchild(i:TImage,y) Function setimagerotationwhenchild(i:TImage,x) |
| ||
@ImaginaryHuman Your stencil functions look really interesting. I'm trying to achieve so that I draw shadows on certain images but not on the distant backgrounds but my attempts to do this with your functions are being ignored :) 1) I use GClearStencil() at the top of my loop (just as I CLS for the backbuffer) 2) I call GStencilRecord(False) before drawing my background 3) I call GStencilRecord(True) before I draw objects that I want to receive a shadow 4) I call GStencilling(True) before I draw my shadows 5) I call GStencilling(False) after I drew my shadows This may be totally incorrect but it's what I gathered from your instructions above :) Also, I'm just using "drawimage" and no fancy surfaces, but it works with glAlphaFunc so I suspect it should work with drawimage command for stencils as well? Here is my attempt att combinding your functions with another test for glAlphaFunc shadows: SuperStrict Type TBox Global i:Int = 0 Field _r:Int, _g:Int, _b:Int Field _x:Float, _y:Float Field _w:Float, _h:Float Method Update() _x :+ (20 * Sin(i + _y)) i:+1 EndMethod Function Create:TBox(x:Float, y:Float, r:Int, g:Int, b:Int) Local box:TBox = New TBox box._x = x box._y = y box._r = r box._g = g box._b = b Return box EndFunction End Type Type TBall Global i:Int = 0 Field _r:Int, _g:Int, _b:Int Field _x:Float, _y:Float Method Update() _y :+ (10 * Sin(i + _x)) i:+1 EndMethod Function Create:TBall(x:Float, y:Float, r:Int, g:Int, b:Int) Local ball:TBall = New TBall ball._x = x ball._y = y ball._r = r ball._g = g ball._b = b Return ball EndFunction EndType SetGraphicsDriver GLMax2DDriver() Graphics 800,600 ' Make image to draw with Global image:TImage = CreateImage( 100,100 ) Cls SetColor 255,255,255 DrawOval 50,50,50,50 GrabImage image,0,0 ' Make box to draw with Global bimage:TImage = CreateImage( 100,100 ) Cls SetColor 255,255,255 DrawRect 0,0,100,100 GrabImage bimage,0,0 Global ballList:TList = New TList Global boxList:TList = New TList Global shadowMode:Int = 0 ' Make some objects to render ballList.AddLast( TBall.Create( 30,150, 255,0,0 ) ) ballList.AddLast( TBall.Create( 50,150, 0,255,0 ) ) ballList.AddLast( TBall.Create( 70,150, 0,0,255 ) ) ballList.AddLast( TBall.Create( 90,150, 255,0,255 ) ) ballList.AddLast( TBall.Create( 110,150, 255,255,0 ) ) boxList.AddLast( TBox.Create( Rand(10,700), Rand(10,500), Rand(100,255), Rand(100,255), Rand(100,255))) boxList.AddLast( TBox.Create( Rand(10,700), Rand(10,500), Rand(100,255), Rand(100,255), Rand(100,255))) boxList.AddLast( TBox.Create( Rand(10,700), Rand(10,500), Rand(100,255), Rand(100,255), Rand(100,255))) boxList.AddLast( TBox.Create( Rand(10,700), Rand(10,500), Rand(100,255), Rand(100,255), Rand(100,255))) boxList.AddLast( TBox.Create( Rand(10,700), Rand(10,500), Rand(100,255), Rand(100,255), Rand(100,255))) Function RenderBackground() For Local i:Int = 0 To GraphicsHeight() Step 10 SetColor Rand(100,155), Rand(100,155), Rand(100,155) DrawRect 0, i, GraphicsWidth(), i + (GraphicsHeight()/10) Next EndFunction Function RenderObjectDepthTestShadows() ' Draw shadows glEnable GL_DEPTH_TEST SetColor 0,0,0 SetAlpha 0.3 glEnable GL_ALPHA_TEST glAlphaFunc GL_GREATER, 0.25 For Local ball:TBall = EachIn ballList DrawImage image, ball._x + 20, ball._y + 20 Next glDisable GL_ALPHA_TEST glDisable GL_DEPTH_TEST EndFunction Function RenderObjectShadowsNoDepthTest() ' Draw shadows SetColor 0,0,0 SetAlpha 0.3 For Local ball:TBall = EachIn ballList DrawImage image, ball._x + 20, ball._y + 20 Next EndFunction Function RenderBoxes() SetAlpha 1.0 For Local box:TBox = EachIn boxList SetColor box._r, box._g, box._b DrawImage bimage, box._x, box._y If Not KeyDown( KEY_SPACE ) box.Update() EndIf Next EndFunction Function RenderObjects() SetAlpha 1.0 For Local ball:TBall = EachIn ballList SetColor ball._r, ball._g, ball._b DrawImage image, ball._x, ball._y If Not KeyDown( KEY_SPACE ) ball.Update() EndIf Next EndFunction SetBlend ALPHABLEND glClearColor 255, 255,255,255 While Not KeyHit( KEY_ESCAPE ) GClearStencil() glClear GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT GStencilRecord(True) RenderBackground() RenderBoxes() GStencilling(True) If shadowMode RenderObjectDepthTestShadows() Else RenderObjectShadowsNoDepthTest() EndIf GStencilling(False) RenderObjects() SetColor 255,255,255 DrawText "DepthTest/AlphaTest shadow rendering - hold SPACE to pause", 100, 10 DrawText "Press M to toggle Depth/Alpha shadow mode on/off", 100, 30 Flip If KeyHit( KEY_M ) shadowMode = 1-shadowMode EndIf Wend 'GL stencil testing modes Global GStencil:Int=False 'Whether to stencil/mask drawn pixels using the stencil buffer content Global GStenMode:Int=GL_ALWAYS 'What GL mode To test the stencil with To determine whether To draw pixels Global GStenThreshold:Int=0 'The stencil test reference value Global GStenReadMask:Int=$FFFFFFFF 'A mask AND'ed with the threshold value and stencil-buffer-pixel when doing a test, to test against specific bits Global GStenWriteMask:Int=$FFFFFFFF 'A mask AND'ed with the stencil pixel being written to write only to specific bits Global GStenRecord:Int=False 'Whether to record new stencil content using incoming fragments Global GStenRecordFailMode:Int=GL_REPLACE 'What GL mode to record stencil data to the stencil buffer when the stencil test fails Global GStenRecordZFailMode:Int=GL_REPLACE 'What GL mode to record stencil data to the stencil buffer when the Z-buffer test fails but the stencil test passes Global GStenRecordZPassMode:Int=GL_REPLACE 'What GL mode to record stencil data to the stencil buffer when the stencil test passes and the depth test fails (or is not used) Global GBegun:Int=-1 Function GStencilRecord(DoRecording:Int=False,FailMode:Int=GL_REPLACE,ZFailMode:Int=GL_REPLACE,ZPassMode:Int=GL_REPLACE) 'Set whether to record new drawn geometry into the stencil, and in what mode based on the result of stencil and depth tests 'Allowed: GL_KEEP, GL_ZERO, GL_REPLACE, GL_INCR, GL_DECR, and GL_INVERT 'Make sure we're not inside a glBegin-glEnd block If GBegun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Switch stencil recording on or off and set its mode If DoRecording=True glStencilMask(GStenWriteMask) 'Set it glStencilFunc(GStenMode,GStenThreshold,GStenReadMask) 'Define the test function glStencilOp(FailMode,ZFailMode,ZPassMode) 'Define the recording operation glEnable(GL_STENCIL_TEST) 'Switch on testing so that the record works, even if testing is GL_ALWAYS GStenRecordFailMode=FailMode 'Store mode GStenRecordZFailMode=ZFailMode 'Store mode GStenRecordZPassMode=ZPassMode 'Store mode GStenRecord=True 'Recording Return Else glStencilMask(GStenWriteMask) 'Set it glStencilFunc(GStenMode,GStenThreshold,GStenReadMask) 'Define the test function glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP) 'Define the recording operation If GStenMode=GL_ALWAYS Then glDisable(GL_STENCIL_TEST) 'Switch off stencilling if not required GStenRecordFailMode=GL_KEEP 'Store mode (if you switch stencil record off, recording mode resets) GStenRecordZFailMode=GL_KEEP GStenRecordZPassMode=GL_KEEP GStenRecord=False 'No recording Return EndIf End Function Function GStencilling(DoStencilling:Int=False,Mode:Int=GL_ALWAYS) 'Change whether to use the stencil to restrict drawing, and in what mode 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Switch stencilling on or off and set the mode If DoStencilling=True glStencilMask(GStenWriteMask) 'Set it glStencilFunc(Mode,GStenThreshold,GStenReadMask) 'Set it glStencilOp(GStenRecordFailMode,GStenRecordZFailMode,GStenRecordZPassMode) 'Set the stencil op glEnable(GL_STENCIL_TEST) 'Enable testing GStenMode=Mode 'Store the mode GStencil=True 'Store state Return Else glStencilMask(GStenWriteMask) 'Set it glStencilFunc(Mode,GStenThreshold,GStenReadMask) 'Set it glStencilOp(GStenRecordFailMode,GStenRecordZFailMode,GStenRecordZPassMode) 'Set the stencil op If GStenRecordFailMode=GL_KEEP And GStenRecordZFailMode=GL_KEEP And GStenRecordZPassMode=GL_KEEP Then glDisable(GL_STENCIL_TEST) 'Disable testing if not required GStenMode=Mode 'Store the mode GStencil=False 'Store state Return EndIf End Function Function GStencilThreshold(Threshold:Int=0) 'Set the stencil compare value - the value from the stencil at which pixels are allowed to be drawn 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Set the threshold glStencilFunc(GStenMode,Threshold,GStenReadMask) 'Set it GStenThreshold=Threshold 'Store the threshold End Function Function GStencilWriteMask(Mask:Int=$FFFFFFFF) 'Change the bit-mask used in stencil testing to confine which bits are writeable 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Set the mask glStencilMask(Mask) 'Set it GStenWriteMask=Mask 'Store the mask End Function Function GStencilReadMask(Mask:Int=$FFFFFFFF) 'Change the bit-mask used in stencil testing to confine which bits are readable during testing 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Set the mask GStenReadMask=Mask 'Store the mask glStencilFunc(GStenMode,GStenThreshold,GStenReadMask) 'Set it End Function Function GClearStencil(Value:Int=0) 'Clear the stencil buffer to a given value 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Clear it glClearStencil(Value) 'Set the clear value glClear(GL_STENCIL_BUFFER_BIT) 'Clear the stencil buffer End Function Function GOutput(AllowRed:Int=GL_FALSE,AllowGreen:Int=GL_FALSE,AllowBlue:Int=GL_FALSE,AllowAlpha:Int=GL_FALSE) 'Define which of the color-buffers channels are enabled for writing output 'Allowed GL_TRUE or GL_FALSE as parameters 'Make sure we're not inside a glBegin-glEnd block If GBEgun<>-1 glEnd() 'MUST end the geometry GBegun=-1 'Ended all glBegins EndIf 'Define output channels glColorMask(AllowRed,AllowGreen,AllowBlue,AllowAlpha) 'Set it End Function Function GMultiBegin(Shape:Int=GL_QUADS) 'Handle multiple calls to glBegin of the same or differnt geometry type 'If we're already inside a glBegin of a particular type, another glBegin 'will not be issued if Shape is the same. When Shape changes to a different 'type of geometry, we glEnd() the current type and start a new glBegin type. 'Be aware that only certain OpenGL commands are allowed inside a glBegin-glEnd 'pair, so make sure to GMultiEnd() before issuing those commands. 'Note that using GMultiBegin without GMultiEnd, geometry may not be drawn 'until a GMultiEnd is called (like a flush command). You can make multiple calls to 'GMultiBegin() without calling GMultiEnd() until later when you are sure you want to flush 'Begin? If GBegun=-1 'Begin a new shape glBegin(Shape) 'Begin a new shape GBegun=Shape 'We have begun this shape, need a glEnd() to follow Return Else 'Begun already, begin a different shape? If GBegun<>Shape glEnd() glBegin(Shape) 'Begin a new, different shape GBegun=Shape 'We are beginning a new shape, need a glEnd() to follow EndIf Return EndIf End Function Function GMultiEnd() 'To finish a block started with MultiBegin() 'This is a substitute for glEnd() which takes into account the state of GMultiBegin 'GMultiBegin will automatically insert a glEnd() if changing geometry type, 'but if you need to end a geometry definition and start using commands which are 'not allowed inside a glBegin/glEnd block, you need to issue a GMultiEnd. 'Note that if geometry is being defined open-endedly by not calling GMultiEnd 'very often, geometry may not be drawn until GMultiEnd is called to complete it. 'but you can make multiple calls to GMultiBegin() and only call GmultiEnd() when 'you want to use commands which don't work in a glBegin-glEnd block. GMultiBegin will 'automatically call glEnd() if changing geometry type. 'End? If GBegun<>-1 glEnd() 'End the geometry GBegun=-1 'Ended all glBegins EndIf End Function |
| ||
Well, OpenGL's stencil system is a little bit convoluted and hard to grasp which is why I made a bunch of stencil functions to try to simplify it, but unfortunately there are still some quirks which catch me out. Sometimes I think that you have to make sure you are properly specifying the stencil threshold, stencil masks, and making sure stencil testing is on when you want to record. In your code you make a call to GStencilRecording(True) which accepts the default parameters for the other params - which is GL_REPLACE, which means the `reference value` is placed into the stencil buffer pixels. But in your code there is no definition of what the threshold should be, so it might be 0. You also probably want to make sure the masks are set up. And you also want to explicitly set stencilling to on - which boils down to the most counter-intuitive thing about OpenGL stencils - you must have testing enabled in order to record to the stencil! It has to pass the stencil test (even if `always` passing regardless of stencil content), in order for the flow to proceed to modifying the stencil buffer. It seems backwards because you'd think you only need to test the stencil when you want to use it to stop stuff being drawn on the screen, but it has to also be `tested` in order to record anything to the stencil. The stencil operation GL_ALWAYS in glStencilOp() (within GStencilRecording) basically says `test the stencil buffer and always allow the incoming pixel to be write the threshold value to the stencil` ... whereas it could also say something like `test the stencil buffer and only write the threshold value to the stencil if the stencil value is greater than or equal to 20`, etc. It gets a bit loopy to get your head around the flow of it. As an example, the following five commands should allow recording to the stencil buffer. If it doesn't work, try changing the stencil threshold to 0 or change the GL_REPLACE to something else. GStencilWriteMask($FF) GStencilReadMask($FF) GStencilThreshold($FF) GStencilRecord(True,GL_KEEP,GL_KEEP,GL_REPLACE) GStencilling(True,GL_ALWAYS) For me, with a stencil threshold of 0 and changing GL_REPLACE to GL_INVERT allows me to definitely draw to the stencil using an `inversion` of what's already in the stencil (like a NOT operation). I defined GStencilRecord and GStencilling separately even though they do similar things because sometimes you want to specify the system differently. But generally I think you should use GStencilling() in addition to GStencilRecord(). And it's better to define all the parameters to make sure you get what you want. The whole thing about stencil threshold and testing needs some trial and error sometimes to get it right. Notice that GStencilling(False) doesn't necessarily switch stencil testing off! If you switch recording off it sets the stencil test operations to GL_KEEP and only then would GStencilling(False) switch off the stencil test. This is because if you are doing any kind of recording that modifies the stencil buffer it has to keep stencil testing switched on otherwise nothing will record. So you might be calling GStencilling(False) but it still keeps stencil testing on, knowing that you are still trying to record. So in your step 4 you switch recording on and stencilling on, but then you switch stencilling off, but because you didn't switch recording off the stencil test will remain active. This probably will then carry over to the next iteration of your loop and cause something to happen that shouldn't happen, resulting in unexpected behavior. So you probably want to make sure that if you really are done with recording and you don't want to test the stencil, switch recording off first and then switch stencilling (the test) off as well. Your step 2 is also a bit useless without also calling GStencilling(False) after it. |
| ||
Hello folks! I just ran across this thread while looking for s.th. different - but... are you aware of Brucey's Cairo wrapper? Cairo is an advanced 2D randering package and is used for some Linux GUIs and web page rendering. And it also renders into PDF and PS documents! With Pango it would also have professional text rendering (including right-to-left and vertical). Thus, wouldn't it be more efficient to - help Brucey adding GL support (e.g. not rendering into an intermediate image) - provide an additional Pango wrapper BlitzMAX would thus get a really professional 2D rendering facility! |
| ||
dunno how to do it |
| ||
I wonder if Cairo is fast enough for doing real time stuff ? I have see some Proof of Concept but never a complete project with good graphics using it. A true Open GL support would be nice indeed ! |
| ||
Well, Cairo itself is already used for rendering of complete GUIs - but presumably with hardware acceleration only. For that reason, adding GL support would be fantastic! |
| ||
Cairo is already( start at line 31) hardware-accelerated and I think Brucey is going to wait until it is close to stable. Lets let the bugs and quirks be found by the Cairo developers before we start trying to use it. |
| ||
Aah, good to know, as Cairo is a powerful package and I admire Brucey's effort to write a BlitzMAX wrapper for it! (Now there is just Pango missing) |