diff --git a/irrlicht_1.5_update/README b/irrlicht_1.5_update/README new file mode 100644 index 000000000..2d0522205 --- /dev/null +++ b/irrlicht_1.5_update/README @@ -0,0 +1,13 @@ +The files in this directory should replace the corresponding +files in an irrlicht-1.5 distribution. They add a new function +draw2DPolygon (with different parameters than the existing +function with the same name). The new function is used to +draw the speedometer, and the track display with the kart +symbols on it. + +If an unpatched version of irrlicht is used, STK will still +compile, but the above mentioned elements will be missing. + +We hope that this function (or a similar one) will be +included in the next irrlicht release, making the use of +a patched version unnecessary. diff --git a/irrlicht_1.5_update/include/IVideoDriver.h b/irrlicht_1.5_update/include/IVideoDriver.h new file mode 100644 index 000000000..6394e618e --- /dev/null +++ b/irrlicht_1.5_update/include/IVideoDriver.h @@ -0,0 +1,1043 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_I_VIDEO_DRIVER_H_INCLUDED__ +#define __IRR_I_VIDEO_DRIVER_H_INCLUDED__ + +#include "rect.h" +#include "SColor.h" +#include "ITexture.h" +#include "irrArray.h" +#include "matrix4.h" +#include "plane3d.h" +#include "dimension2d.h" +#include "position2d.h" +#include "SMaterial.h" +#include "IMeshBuffer.h" +#include "triangle3d.h" +#include "EDriverTypes.h" +#include "EDriverFeatures.h" + +namespace irr +{ +namespace io +{ + class IAttributes; + class IReadFile; +} // end namespace io +namespace scene +{ + class IMeshBuffer; + class IMeshManipulator; +} // end namespace scene + +namespace video +{ + struct S3DVertex; + struct S3DVertex2TCoords; + struct S3DVertexTangents; + struct SLight; + struct SExposedVideoData; + class IImageLoader; + class IImageWriter; + class IMaterialRenderer; + class IGPUProgrammingServices; + + //! enumeration for geometry transformation states + enum E_TRANSFORMATION_STATE + { + //! View transformation + ETS_VIEW = 0, + //! World transformation + ETS_WORLD, + //! Projection transformation + ETS_PROJECTION, + //! Texture transformation + ETS_TEXTURE_0, + //! Texture transformation + ETS_TEXTURE_1, + //! Texture transformation + ETS_TEXTURE_2, + //! Texture transformation + ETS_TEXTURE_3, + //! Not used + ETS_COUNT + }; + + enum E_LOST_RESSOURCE + { + //! The whole device/driver is lost + ELR_DEVICE = 1, + //! All texture are lost, rare problem + ELR_TEXTURES = 2, + //! The Render Target Textures are lost, typical problem for D3D + ELR_RTTS = 4, + //! The HW buffers are lost, will be recreated automatically, but might require some more time this frame + ELR_HW_BUFFERS = 8 + }; + + //! Interface to driver which is able to perform 2d and 3d graphics functions. + /** This interface is one of the most important interfaces of + the Irrlicht Engine: All rendering and texture manipulation is done with + this interface. You are able to use the Irrlicht Engine by only + invoking methods of this interface if you like to, although the + irr::scene::ISceneManager interface provides a lot of powerful classes + and methods to make the programmer's life easier. + */ + class IVideoDriver : public virtual IReferenceCounted + { + public: + + //! Applications must call this method before performing any rendering. + /** This method can clear the back- and the z-buffer. + \param backBuffer Specifies if the back buffer should be + cleared, which means that the screen is filled with the color + specified. If this parameter is false, the back buffer will + not be cleared and the color parameter is ignored. + \param zBuffer Specifies if the depth buffer (z buffer) should + be cleared. It is not nesesarry to do so if only 2d drawing is + used. + \param color The color used for back buffer clearing + \param windowId Handle of another window, if you want the + bitmap to be displayed on another window. If this is null, + everything will be displayed in the default window. + Note: This feature is not fully implemented for all devices. + \param sourceRect Pointer to a rectangle defining the source + rectangle of the area to be presented. Set to null to present + everything. Note: not implemented in all devices. + \return False if failed. */ + virtual bool beginScene(bool backBuffer=true, bool zBuffer=true, + SColor color=SColor(255,0,0,0), + void* windowId=0, + core::rect* sourceRect=0) = 0; + + //! Presents the rendered image to the screen. + /** Applications must call this method after performing any + rendering. + \return False if failed and true if succeeded. */ + virtual bool endScene() = 0; + + //! Queries the features of the driver. + /** Returns true if a feature is available + \param feature Feature to query. + \return True if the feature is available, false if not. */ + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const = 0; + + //! Disable a feature of the driver. + /** Can also be used to enable the features again. It is not + possible to enable unsupported features this way, though. + \param feature Feature to disable. + \param flag When true the feature is disabled, otherwise it is enabled. */ + virtual void disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag=true) =0; + + //! Check if the driver was recently reset. + /** For d3d devices you will need to recreate the RTTs if the + driver was reset. Should be queried right after beginScene(). + */ + virtual bool checkDriverReset() =0; + + //! Sets transformation matrices. + /** \param state Transformation type to be set, e.g. view, + world, or projection. + \param mat Matrix describing the transformation. */ + virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) = 0; + + //! Returns the transformation set by setTransform + /** \param state Transformation type to query + \return Matrix describing the transformation. */ + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const = 0; + + //! Sets a material. + /** All 3d drawing functions will draw geometry using this material thereafter. + \param material: Material to be used from now on. */ + virtual void setMaterial(const SMaterial& material) = 0; + + //! Get access to a named texture. + /** Loads the texture from disk if it is not + already loaded and generates mipmap levels if desired. + Texture loading can be influenced using the + setTextureCreationFlag() method. The texture can be in several + imageformats, such as BMP, JPG, TGA, PCX, PNG, and PSD. + \param filename Filename of the texture to be loaded. + \return Pointer to the texture, or 0 if the texture + could not be loaded. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual ITexture* getTexture(const c8* filename) = 0; + + //! Get access to a named texture. + /** Loads the texture from disk if it is not + already loaded and generates mipmap levels if desired. + Texture loading can be influenced using the + setTextureCreationFlag() method. The texture can be in several + imageformats, such as BMP, JPG, TGA, PCX, PNG, and PSD. + \param filename Filename of the texture to be loaded. + \return Pointer to the texture, or 0 if the texture + could not be loaded. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual ITexture* getTexture(const core::stringc& filename) = 0; + + //! Get access to a named texture. + /** Loads the texture from disk if it is not + already loaded and generates mipmap levels if desired. + Texture loading can be influenced using the + setTextureCreationFlag() method. The texture can be in several + imageformats, such as BMP, JPG, TGA, PCX, PNG, and PSD. + \param file Pointer to an already opened file. + \return Pointer to the texture, or 0 if the texture + could not be loaded. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual ITexture* getTexture(io::IReadFile* file) = 0; + + //! Returns a texture by index + /** \param index: Index of the texture, must be smaller than + getTextureCount() Please note that this index might change when + adding or removing textures + \return Pointer to the texture, or 0 if the texture was not + set or index is out of bounds. This pointer should not be + dropped. See IReferenceCounted::drop() for more information. */ + virtual ITexture* getTextureByIndex(u32 index) = 0; + + //! Returns amount of textures currently loaded + /** \return Amount of textures currently loaded */ + virtual u32 getTextureCount() const = 0; + + //! Renames a texture + /** \param texture Pointer to the texture to rename. + \param newName New name for the texture. This should be a unique name. */ + virtual void renameTexture(ITexture* texture, const c8* newName) = 0; + + //! Creates an empty texture of specified size. + /** \param size: Size of the texture. + \param name A name for the texture. Later calls to + getTexture() with this name will return this texture + \param format Desired color format of the texture. Please note + that the driver may choose to create the texture in another + color format. + \return Pointer to the newly created texture. This pointer + should not be dropped. See IReferenceCounted::drop() for more + information. */ + virtual ITexture* addTexture(const core::dimension2d& size, + const c8* name, ECOLOR_FORMAT format = ECF_A8R8G8B8) = 0; + + //! Creates a texture from an IImage. + /** \param name A name for the texture. Later calls of + getTexture() with this name will return this texture + \param image Image the texture is created from. + \return Pointer to the newly created texture. This pointer + should not be dropped. See IReferenceCounted::drop() for more + information. */ + virtual ITexture* addTexture(const c8* name, IImage* image) = 0; + + //! Adds a new render target texture to the texture cache. + /** \param size Size of the texture, in pixels. Width and + height should be a power of two (e.g. 64, 128, 256, 512, ...) + and it should not be bigger than the backbuffer, because it + shares the zbuffer with the screen buffer. + \param name An optional name for the RTT. + \return Pointer to the created texture or 0 if the texture + could not be created. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const c8* name=0) =0; + + //! Adds a new render target texture + /** \deprecated use addRenderTargetTexture instead. */ + virtual ITexture* createRenderTargetTexture(const core::dimension2d& size, + const c8* name=0) =0; + + //! Removes a texture from the texture cache and deletes it. + /** This method can free a lot of memory! + Please note that after calling this, the pointer to the + ITexture may no longer be valid, if it was not grabbed before + by other parts of the engine for storing it longer. So it is a + good idea to set all materials which are using this texture to + 0 or another texture first. + \param texture Texture to delete from the engine cache. */ + virtual void removeTexture(ITexture* texture) = 0; + + //! Removes all textures from the texture cache and deletes them. + /** This method can free a lot of memory! + Please note that after calling this, the pointer to the + ITexture may no longer be valid, if it was not grabbed before + by other parts of the engine for storing it longer. So it is a + good idea to set all materials which are using this texture to + 0 or another texture first. */ + virtual void removeAllTextures() = 0; + + //! Remove hardware buffer + virtual void removeHardwareBuffer(const scene::IMeshBuffer* mb) = 0; + + //! Remove all hardware buffers + virtual void removeAllHardwareBuffers() = 0; + + //! Creates a 1bit alpha channel of the texture based of an color key. + /** This makes the texture transparent at the regions where + this color key can be found when using for example draw2DImage + with useAlphachannel==true. + \param texture Texture whose alpha channel is modified. + \param color Color key color. Every pixel with this color will + become transparent as described above. Please note that the + colors of a texture may be converted when loading it, so the + color values may not be exactly the same in the engine and for + example in picture edit programs. To avoid this problem, you + could use the makeColorKeyTexture method, which takes the + position of a pixel instead a color value. */ + virtual void makeColorKeyTexture(video::ITexture* texture, video::SColor color) const = 0; + + //! Creates a 1bit alpha channel of the texture based of an color key position. + /** This makes the texture transparent at the regions where + this color key can be found when using for example draw2DImage + with useAlphachannel==true. + \param texture Texture whose alpha channel is modified. + \param colorKeyPixelPos Position of a pixel with the color key + color. Every pixel with this color will become transparent as + described above. */ + virtual void makeColorKeyTexture(video::ITexture* texture, + core::position2d colorKeyPixelPos) const = 0; + + //! Creates a normal map from a height map texture. + /** If the target texture has 32 bit, the height value is + stored in the alpha component of the texture as addition. This + value is used by the video::EMT_PARALLAX_MAP_SOLID material and + similar materials. + \param texture Texture whose alpha channel is modified. + \param amplitude Constant value by which the height + information is multiplied.*/ + virtual void makeNormalMapTexture(video::ITexture* texture, f32 amplitude=1.0f) const = 0; + + //! Sets a new render target. + /** This will only work if the driver supports the + EVDF_RENDER_TO_TARGET feature, which can be queried with + queryFeature(). Usually, rendering to textures is done in this + way: + \code + // create render target + ITexture* target = driver->addRenderTargetTexture(core::dimension2d(128,128), "rtt1"); + + // ... + + driver->setRenderTarget(target); // set render target + // .. draw stuff here + driver->setRenderTarget(0); // set previous render target + \endcode + Please note that you cannot render 3D or 2D geometry with a + render target as texture on it when you are rendering the scene + into this render target at the same time. It is usually only + possible to render into a texture between the + IVideoDriver::beginScene() and endScene() method calls. + \param texture New render target. Must be a texture created with + IVideoDriver::addRenderTargetTexture(). If set to 0, it sets + the previous render target which was set before the last + setRenderTarget() call. + \param clearBackBuffer Clears the backbuffer of the render + target with the color parameter + \param clearZBuffer Clears the zBuffer of the rendertarget. + Note that because the frame buffer may share the zbuffer with + the rendertarget, its zbuffer might be partially cleared too + by this. + \param color The background color for the render target. + \return True if sucessful and false if not. */ + virtual bool setRenderTarget(video::ITexture* texture, + bool clearBackBuffer=true, bool clearZBuffer=true, + SColor color=video::SColor(0,0,0,0)) = 0; + + //! Sets a new viewport. + /** Every rendering operation is done into this new area. + \param area: Rectangle defining the new area of rendering + operations. */ + virtual void setViewPort(const core::rect& area) = 0; + + //! Gets the area of the current viewport. + /** \return Rectangle of the current viewport. */ + virtual const core::rect& getViewPort() const = 0; + + //! Draws a vertex primitive list + /** Note that there may be at maximum 65536 vertices, because + the index list is an array of 16 bit values each with a maximum + value of 65536. If there are more than 65536 vertices in the + list, results of this operation are not defined. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param primCount Amount of Primitives + \param vType Vertex type, e.g. EVT_STANDARD for S3DVertex. + \param pType Primitive type, e.g. EPT_TRIANGLE_FAN for a triangle fan. */ + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) = 0; + + //! Draws an indexed triangle list. + /** Note that there may be at maximum 65536 vertices, because + the index list is an array of 16 bit values each with a maximum + value of 65536. If there are more than 65536 vertices in the + list, results of this operation are not defined. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param triangleCount Amount of Triangles. Usually amount of indices / 3. */ + virtual void drawIndexedTriangleList(const S3DVertex* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + + //! Draws an indexed triangle list. + /** Note that there may be at maximum 65536 vertices, because + the index list is an array of 16 bit values each with a maximum + value of 65536. If there are more than 65536 vertices in the + list, results of this operation are not defined. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param triangleCount Amount of Triangles. Usually amount of indices / 3. */ + virtual void drawIndexedTriangleList(const S3DVertex2TCoords* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + + //! Draws an indexed triangle list. + /** Note that there may be at maximum 65536 vertices, because + the index list is an array of 16 bit values each with a maximum + value of 65536. If there are more than 65536 vertices in the + list, results of this operation are not defined. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param triangleCount Amount of Triangles. Usually amount of indices / 3. */ + virtual void drawIndexedTriangleList(const S3DVertexTangents* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + + //! Draws an indexed triangle fan. + /** Note that there may be at maximum 65536 vertices, because + the index list is an array of 16 bit values each with a maximum + value of 65536. If there are more than 65536 vertices in the + list, results of this operation are not defined. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param triangleCount Amount of Triangles. Usually amount of indices - 2. */ + virtual void drawIndexedTriangleFan(const S3DVertex* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + + //! Draws an indexed triangle fan. + /** Note that there may be at maximum 65536 vertices, because + the index list is an array of 16 bit values each with a maximum + value of 65536. If there are more than 65536 vertices in the + list, results of this operation are not defined. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param triangleCount Amount of Triangles. Usually amount of indices - 2. */ + virtual void drawIndexedTriangleFan(const S3DVertex2TCoords* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + + //! Draws a 3d line. + /** For some implementations, this method simply calls + drawIndexedTriangles for some triangles. + Note that the line is drawn using the current transformation + matrix and material. So if you need to draw the 3D line + independently of the current transformation, use + \code + driver->setMaterial(unlitMaterial); + driver->setTransform(video::ETS_WORLD, core::matrix4()); + \endcode + for some properly set up material before drawing the line. + Some drivers support line thickness set in the material. + \param start Start of the 3d line. + \param end End of the 3d line. + \param color Color of the line. */ + virtual void draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color = SColor(255,255,255,255)) = 0; + + //! Draws a 3d triangle. + /** This method calls drawIndexedTriangles for some triangles. + This method works with all drivers because it simply calls + drawIndexedTriangleList but it is hence not very fast. + Note that the triangle is drawn using the current + transformation matrix and material. So if you need to draw it + independently of the current transformation, use + \code + driver->setMaterial(unlitMaterial); + driver->setTransform(video::ETS_WORLD, core::matrix4()); + \endcode + for some properly set up material before drawing the triangle. + \param triangle The triangle to draw. + \param color Color of the line. */ + virtual void draw3DTriangle(const core::triangle3df& triangle, + SColor color = SColor(255,255,255,255)) = 0; + + //! Draws a 3d axis aligned box. + /** This method simply calls draw3DLine for the edges of the + box. Note that the box is drawn using the current transformation + matrix and material. So if you need to draw it independently of + the current transformation, use + \code + driver->setMaterial(unlitMaterial); + driver->setTransform(video::ETS_WORLD, core::matrix4()); + \endcode + for some properly set up material before drawing the box. + \param box The axis aligned box to draw + \param color Color to use while drawing the box. */ + virtual void draw3DBox(const core::aabbox3d& box, + SColor color = SColor(255,255,255,255)) = 0; + + //! Draws a 2d image without any special effects + /** \param texture Pointer to texture to use. + \param destPos Upper left 2d destination position where the + image will be drawn. */ + virtual void draw2DImage(const video::ITexture* texture, + const core::position2d& destPos) = 0; + + //! Draws a 2d image using a color + /** (if color is other than + Color(255,255,255,255)) and the alpha channel of the texture. + \param texture Texture to be drawn. + \param destPos Upper left 2d destination position where the + image will be drawn. + \param sourceRect Source rectangle in the image. + \param clipRect Pointer to rectangle on the screen where the + image is clipped to. + If this pointer is NULL the image is not clipped. + \param color Color with which the image is drawn. If the color + equals Color(255,255,255,255) it is ignored. Note that the + alpha component is used: If alpha is other than 255, the image + will be transparent. + \param useAlphaChannelOfTexture: If true, the alpha channel of + the texture is used to draw the image.*/ + virtual void draw2DImage(const video::ITexture* texture, const core::position2d& destPos, + const core::rect& sourceRect, const core::rect* clipRect = 0, + SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false) = 0; + + //! Draws a set of 2d images, using a color and the alpha channel of the texture. + /** The images are drawn beginning at pos and concatenated in + one line. All drawings are clipped against clipRect (if != 0). + The subtextures are defined by the array of sourceRects and are + chosen by the indices given. + \param texture Texture to be drawn. + \param pos Upper left 2d destination position where the image + will be drawn. + \param sourceRects Source rectangles of the image. + \param indices List of indices which choose the actual + rectangle used each time. + \param kerningWidth Offset to Position on X + \param clipRect Pointer to rectangle on the screen where the + image is clipped to. + If this pointer is 0 then the image is not clipped. + \param color Color with which the image is drawn. + Note that the alpha component is used. If alpha is other than + 255, the image will be transparent. + \param useAlphaChannelOfTexture: If true, the alpha channel of + the texture is used to draw the image. */ + virtual void draw2DImage(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + s32 kerningWidth=0, + const core::rect* clipRect=0, + SColor color=SColor(255,255,255,255), + bool useAlphaChannelOfTexture=false) = 0; + + //! Draws a part of the texture into the rectangle. Note that colors must be an array of 4 colors if used. + /** Suggested and first implemented by zola. + \param texture The texture to draw from + \param destRect The rectangle to draw into + \param sourceRect The rectangle denoting a part of the texture + \param clipRect Clips the destination rectangle (may be 0) + \param colors Array of 4 colors denoting the color values of + the corners of the destRect + \param useAlphaChannelOfTexture True if alpha channel will be + blended. */ + virtual void draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect = 0, + const video::SColor * const colors=0, bool useAlphaChannelOfTexture=false) = 0; + + //! Draws a 2d rectangle. + /** \param color Color of the rectangle to draw. The alpha + component will not be ignored and specifies how transparent the + rectangle will be. + \param pos Position of the rectangle. + \param clip Pointer to rectangle against which the rectangle + will be clipped. If the pointer is null, no clipping will be + performed. */ + virtual void draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip = 0) = 0; + + //! Draws an 2d rectangle with a gradient. + /** \param colorLeftUp Color of the upper left corner to draw. + The alpha component will not be ignored and specifies how + transparent the rectangle will be. + \param colorRightUp Color of the upper right corner to draw. + The alpha component will not be ignored and specifies how + transparent the rectangle will be. + \param colorLeftDown Color of the lower left corner to draw. + The alpha component will not be ignored and specifies how + transparent the rectangle will be. + \param colorRightDown Color of the lower right corner to draw. + The alpha component will not be ignored and specifies how + transparent the rectangle will be. + \param pos Position of the rectangle. + \param clip Pointer to rectangle against which the rectangle + will be clipped. If the pointer is null, no clipping will be + performed. */ + virtual void draw2DRectangle(const core::rect& pos, + SColor colorLeftUp, SColor colorRightUp, + SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip = 0) = 0; + + //! Draws a 2d line. + /** \param start: Screen coordinates of the start of the line + in pixels. + \param end: Screen coordinates of the start of the line in + pixels. + \param color: Color of the line to draw. */ + virtual void draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color=SColor(255,255,255,255)) = 0; + + //! Draws a pixel. + /** \param position: the position of the pixel. + \param color: Color of the pixel to draw. */ + virtual void drawPixel(u32 x, u32 y, const SColor & color) = 0; + + //! Draws a non filled concyclic regular 2d polyon. + /** This method can be used to draw circles, but also + triangles, tetragons, pentagons, hexagons, heptagons, octagons, + enneagons, decagons, hendecagons, dodecagon, triskaidecagons, + etc. I think you'll got it now. And all this by simply + specifying the vertex count. Welcome to the wonders of + geometry. + \param center Position of center of circle (pixels). + \param radius Radius of circle in pixels. + \param color Color of the circle. + \param vertexCount Amount of vertices of the polygon. Specify 2 + to draw a line, 3 to draw a triangle, 4 for tetragons and a lot + (>10) for nearly a circle. */ + virtual void draw2DPolygon(core::position2d center, + f32 radius, + video::SColor color=SColor(100,255,255,255), + s32 vertexCount=10) = 0; + + //! Draws a filled convex 2d polyon. + /** This method can be used to draw (approximated) circles + etc., but also any convex 2d polygon. + \param vertices The vertices of the polygon. + \param colors The color for each vertex. If less colors are + specified than there are vertices, color[0] is used! + So to fill a polygon with one colour, you only have to + specify a 1-element array. If NULL, no colour values + are set. + \param texture A texture to apply to the polygon (optional). + \param coordinates Texture coordinates for the polygon (only + used if a texture is specified). + \param useAlphaChannelOfTexture True if alpha channels + of the texture should be used. */ + virtual void draw2DPolygon(const core::array &vertices, + const core::array *colors=NULL, + const video::ITexture *texture=NULL, + bool useAlphaChannelOfTexture=false, + const core::array *coordinates=NULL) {}; +#define IRRLICHT_HAS_SUPERTUXKART_POLYGON 1 + + //! Draws a shadow volume into the stencil buffer. + /** To draw a stencil shadow, do this: First, draw all geometry. + Then use this method, to draw the shadow volume. Then, use + IVideoDriver::drawStencilShadow() to visualize the shadow. + Please note that the code for the opengl version of the method + is based on free code sent in by Philipp Dortmann, lots of + thanks go to him! + \param triangles Pointer to array of 3d vectors, specifying the + shadow volume. + \param count Amount of triangles in the array. + \param zfail If set to true, zfail method is used, otherwise + zpass. */ + virtual void drawStencilShadowVolume(const core::vector3df* triangles, s32 count, bool zfail=true) = 0; + + //! Fills the stencil shadow with color. + /** After the shadow volume has been drawn into the stencil + buffer using IVideoDriver::drawStencilShadowVolume(), use this + to draw the color of the shadow. + Please note that the code for the opengl version of the method + is based on free code sent in by Philipp Dortmann, lots of + thanks go to him! + \param clearStencilBuffer Set this to false, if you want to + draw every shadow with the same color, and only want to call + drawStencilShadow() once after all shadow volumes have been + drawn. Set this to true, if you want to paint every shadow with + its own color. + \param leftUpEdge Color of the shadow in the upper left corner + of screen. + \param rightUpEdge Color of the shadow in the upper right + corner of screen. + \param leftDownEdge Color of the shadow in the lower left + corner of screen. + \param rightDownEdge Color of the shadow in the lower right + corner of screen. */ + virtual void drawStencilShadow(bool clearStencilBuffer=false, + video::SColor leftUpEdge = video::SColor(255,0,0,0), + video::SColor rightUpEdge = video::SColor(255,0,0,0), + video::SColor leftDownEdge = video::SColor(255,0,0,0), + video::SColor rightDownEdge = video::SColor(255,0,0,0)) = 0; + + //! Draws a mesh buffer + /** \param mb: Buffer to draw; */ + virtual void drawMeshBuffer( const scene::IMeshBuffer* mb) = 0; + + //! Sets the fog mode. + /** These are global values attached to each 3d object rendered, + which has the fog flag enabled in its material. + \param color Color of the fog + \param linearFog Set this to true for linear fog, otherwise + exponential fog is applied. + \param start Only used in linear fog mode (linearFog=true). + Specifies where fog starts. + \param end Only used in linear fog mode (linearFog=true). + Specifies where fog ends. + \param density Only used in exponential fog mode + (linearFog=false). Must be a value between 0 and 1. + \param pixelFog Set this to false for vertex fog, and true if + you want per-pixel fog. + \param rangeFog Set this to true to enable range-based vertex + fog. The distance from the viewer is used to compute the fog, + not the z-coordinate. This is better, but slower. This is only + available with D3D and vertex fog. */ + virtual void setFog(SColor color=SColor(0,255,255,255), + bool linearFog=true, f32 start=50.0f, f32 end=100.0f, + f32 density=0.01f, + bool pixelFog=false, bool rangeFog=false) = 0; + + //! Get the current color format of the color buffer + /** \return Color format of the color buffer. */ + virtual ECOLOR_FORMAT getColorFormat() const = 0; + + //! Get the size of the screen or render window. + /** \return Size of screen or render window. */ + virtual const core::dimension2d& getScreenSize() const = 0; + + //! Get the size of the current render target + /** This method will return the screen size if the driver + doesn't support render to texture, or if the current render + target is the screen. + \return Size of render target or screen/window */ + virtual const core::dimension2d& getCurrentRenderTargetSize() const = 0; + + //! Returns current frames per second value. + /** This value is updated approximately every 1.5 seconds and + is only intended to provide a rough guide to the average frame + rate. It is not suitable for use in performing timing + calculations or framerate independent movement. + \return Approximate amount of frames per second drawn. */ + virtual s32 getFPS() const = 0; + + //! Returns amount of primitives (mostly triangles) which were drawn in the last frame. + /** Together with getFPS() very useful method for statistics. + \param mode Defines if the primitives drawn are accumulated or + counted per frame. + \return Amount of primitives drawn in the last frame. */ + virtual u32 getPrimitiveCountDrawn( u32 mode = 0 ) const = 0; + + //! Deletes all dynamic lights which were previously added with addDynamicLight(). + virtual void deleteAllDynamicLights() = 0; + + //! Adds a dynamic light. + /** \param light Data specifying the dynamic light. */ + virtual void addDynamicLight(const SLight& light) = 0; + + //! Returns the maximal amount of dynamic lights the device can handle + /** \return Maximal amount of dynamic lights. */ + virtual u32 getMaximalDynamicLightAmount() const = 0; + + //! Returns amount of dynamic lights currently set + /** \return Amount of dynamic lights currently set */ + virtual u32 getDynamicLightCount() const = 0; + + //! Returns light data which was previously set by IVideoDriver::addDynamicLight(). + /** \param idx Zero based index of the light. Must be 0 or + greater and smaller than IVideoDriver()::getDynamicLightCount. + \return Light data. */ + virtual const SLight& getDynamicLight(u32 idx) const = 0; + + //! Gets name of this video driver. + /** \return Returns the name of the video driver, e.g. in case + of the Direct3D8 driver, it would return "Direct3D 8.1". */ + virtual const wchar_t* getName() const = 0; + + //! Adds an external image loader to the engine. + /** This is useful if the Irrlicht Engine should be able to load + textures of currently unsupported file formats (e.g. gif). The + IImageLoader only needs to be implemented for loading this file + format. A pointer to the implementation can be passed to the + engine using this method. + \param loader Pointer to the external loader created. */ + virtual void addExternalImageLoader(IImageLoader* loader) = 0; + + //! Adds an external image writer to the engine. + /** This is useful if the Irrlicht Engine should be able to + write textures of currently unsupported file formats (e.g + .gif). The IImageWriter only needs to be implemented for + writing this file format. A pointer to the implementation can + be passed to the engine using this method. + \param writer: Pointer to the external writer created. */ + virtual void addExternalImageWriter(IImageWriter* writer) = 0; + + //! Returns the maximum amount of primitives + /** (mostly vertices) which the device is able to render with + one drawIndexedTriangleList call. + \return Maximum amount of primitives. */ + virtual u32 getMaximalPrimitiveCount() const = 0; + + //! Enables or disables a texture creation flag. + /** These flags define how textures should be created. By + changing this value, you can influence for example the speed of + rendering a lot. But please note that the video drivers take + this value only as recommendation. It could happen that you + enable the ETCF_ALWAYS_16_BIT mode, but the driver still creates + 32 bit textures. + \param flag Texture creation flag. + \param enabled Specifies if the given flag should be enabled or + disabled. */ + virtual void setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled) = 0; + + //! Returns if a texture creation flag is enabled or disabled. + /** You can change this value using setTextureCreationMode(). + \param flag Texture creation flag. + \return The current texture creation mode. */ + virtual bool getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const = 0; + + //! Creates a software image from a file. + /** No hardware texture will be created for this image. This + method is useful for example if you want to read a heightmap + for a terrain renderer. + \param filename Name of the file from which the image is + created. + \return The created image. + If you no longer need the image, you should call IImage::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IImage* createImageFromFile(const c8* filename) = 0; + + //! Creates a software image from a file. + /** No hardware texture will be created for this image. This + method is useful for example if you want to read a heightmap + for a terrain renderer. + \param file File from which the image is created. + \return The created image. + If you no longer need the image, you should call IImage::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IImage* createImageFromFile(io::IReadFile* file) = 0; + + //! Writes the provided image to a file. + /** Requires that there is a suitable image writer registered + for writing the image. + \param image Image to write. + \param filename Name of the file to write. + \param param Control parameter for the backend (e.g. compression + level). + \return True on successful write. */ + virtual bool writeImageToFile(IImage* image, const c8* filename, u32 param = 0) = 0; + + //! Creates a software image from a byte array. + /** No hardware texture will be created for this image. This + method is useful for example if you want to read a heightmap + for a terrain renderer. + \param format Desired color format of the texture + \param size Desired size of the image + \param data A byte array with pixel color information + \param ownForeignMemory If true, the image will use the data + pointer directly and own it afterwards. If false, the memory + will by copied internally. + \param deleteMemory Whether the memory is deallocated upon + destruction. + \return The created image. + If you no longer need the image, you should call IImage::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IImage* createImageFromData(ECOLOR_FORMAT format, + const core::dimension2d& size, void *data, + bool ownForeignMemory=false, + bool deleteMemory = true) = 0; + + //! Creates an empty software image. + /** + \param format Desired color format of the image. + \param size Size of the image to create. + \return The created image. + If you no longer need the image, you should call IImage::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IImage* createImage(ECOLOR_FORMAT format, const core::dimension2d& size) =0; + + //! Creates a software image by converting it to given format from another image. + /** + \param format Desired color format of the image. + \param imageToCopy Image to copy to the new image. + \return The created image. + If you no longer need the image, you should call IImage::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IImage* createImage(ECOLOR_FORMAT format, IImage *imageToCopy) =0; + + //! Creates a software image from a part of another image. + /** + \param imageToCopy Image to copy the the new image in part. + \param pos Position of rectangle to copy. + \param size Extents of rectangle to copy. + \return The created image. + If you no longer need the image, you should call IImage::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IImage* createImage(IImage* imageToCopy, + const core::position2d& pos, + const core::dimension2d& size) =0; + + //! Event handler for resize events. Only used by the engine internally. + /** Used to notify the driver that the window was resized. + Usually, there is no need to call this method. */ + virtual void OnResize(const core::dimension2d& size) = 0; + + //! Adds a new material renderer to the video device. + /** Use this method to extend the VideoDriver with new material + types. To extend the engine using this method do the following: + Derive a class from IMaterialRenderer and override the methods + you need. For setting the right renderstates, you can try to + get a pointer to the real rendering device using + IVideoDriver::getExposedVideoData(). Add your class with + IVideoDriver::addMaterialRenderer(). To use an object being + displayed with your new material, set the MaterialType member of + the SMaterial struct to the value returned by this method. + If you simply want to create a new material using vertex and/or + pixel shaders it would be easier to use the + video::IGPUProgrammingServices interface which you can get + using the getGPUProgrammingServices() method. + \param renderer A pointer to the new renderer. + \param name Optional name for the material renderer entry. + \return The number of the material type which can be set in + SMaterial::MaterialType to use the renderer. -1 is returned if + an error occured. For example if you tried to add an material + renderer to the software renderer or the null device, which do + not accept material renderers. */ + virtual s32 addMaterialRenderer(IMaterialRenderer* renderer, const c8* name = 0) = 0; + + //! Get access to a material renderer by index. + /** \param idx Id of the material renderer. Can be a value of + the E_MATERIAL_TYPE enum or a value which was returned by + addMaterialRenderer(). + \return Pointer to material renderer or null if not existing. */ + virtual IMaterialRenderer* getMaterialRenderer(u32 idx) = 0; + + //! Get amount of currently available material renderers. + /** \return Amount of currently available material renderers. */ + virtual u32 getMaterialRendererCount() const = 0; + + //! Get name of a material renderer + /** This string can, e.g., be used to test if a specific + renderer already has been registered/created, or use this + string to store data about materials: This returned name will + be also used when serializing materials. + \param idx Id of the material renderer. Can be a value of the + E_MATERIAL_TYPE enum or a value which was returned by + addMaterialRenderer(). + \return String with the name of the renderer, or 0 if not + exisiting */ + virtual const c8* getMaterialRendererName(u32 idx) const = 0; + + //! Sets the name of a material renderer. + /** Will have no effect on built-in material renderers. + \param idx: Id of the material renderer. Can be a value of the + E_MATERIAL_TYPE enum or a value which was returned by + addMaterialRenderer(). + \param name: New name of the material renderer. */ + virtual void setMaterialRendererName(s32 idx, const c8* name) = 0; + + //! Creates material attributes list from a material + /** This method is useful for serialization and more. + Please note that the video driver will use the material + renderer names from getMaterialRendererName() to write out the + material type name, so they should be set before. + \param material The material to serialize. + \return The io::IAttributes container holding the material + properties. */ + virtual io::IAttributes* createAttributesFromMaterial(const video::SMaterial& material) = 0; + + //! Fills an SMaterial structure from attributes. + /** Please note that for setting material types of the + material, the video driver will need to query the material + renderers for their names, so all non built-in materials must + have been created before calling this method. + \param outMaterial The material to set the properties for. + \param attributes The attributes to read from. */ + virtual void fillMaterialStructureFromAttributes(video::SMaterial& outMaterial, io::IAttributes* attributes) = 0; + + //! Returns driver and operating system specific data about the IVideoDriver. + /** This method should only be used if the engine should be + extended without having to modify the source of the engine. + \return Collection of device dependent pointers. */ + virtual const SExposedVideoData& getExposedVideoData() = 0; + + //! Get type of video driver + /** \return Type of driver. */ + virtual E_DRIVER_TYPE getDriverType() const = 0; + + //! Gets the IGPUProgrammingServices interface. + /** \return Pointer to the IGPUProgrammingServices. Returns 0 + if the video driver does not support this. For example the + Software driver and the Null driver will always return 0. */ + virtual IGPUProgrammingServices* getGPUProgrammingServices() = 0; + + //! Returns a pointer to the mesh manipulator. + virtual scene::IMeshManipulator* getMeshManipulator() = 0; + + //! Clears the ZBuffer. + /** Note that you usually need not to call this method, as it + is automatically done in IVideoDriver::beginScene() or + IVideoDriver::setRenderTarget() if you enable zBuffer. But if + you have to render some special things, you can clear the + zbuffer during the rendering process with this method any time. + */ + virtual void clearZBuffer() = 0; + + //! Make a screenshot of the last rendered frame. + /** \return An image created from the last rendered frame. */ + virtual IImage* createScreenShot() = 0; + + //! Check if the image is already loaded. + /** Works similar to getTexture(), but does not load the texture + if it is not currently loaded. + \param filename Name of the texture. + \return Pointer to loaded texture, or 0 if not found. */ + virtual video::ITexture* findTexture(const c8* filename) = 0; + + //! Set or unset a clipping plane. + /** There are at least 6 clipping planes available for the user + to set at will. + \param index The plane index. Must be between 0 and + MaxUserClipPlanes. + \param plane The plane itself. + \param enable If true, enable the clipping plane else disable + it. + \return True if the clipping plane is usable. */ + virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable=false) = 0; + + //! Enable or disable a clipping plane. + /** There are at least 6 clipping planes available for the user + to set at will. + \param index The plane index. Must be between 0 and + MaxUserClipPlanes. + \param enable If true, enable the clipping plane else disable + it. */ + virtual void enableClipPlane(u32 index, bool enable) = 0; + + //! Returns the graphics card vendor name. + virtual core::stringc getVendorInfo() = 0; + + //! Only used by the engine internally. + /** The ambient color is set in the scene manager, see + scene::ISceneManager::setAmbientLight(). + \param color New color of the ambient light. */ + virtual void setAmbientLight(const SColorf& color) = 0; + + //! Only used by the engine internally. + /** Passes the global material flag AllowZWriteOnTransparent. + Use the SceneManager attribute to set this value from your app. + \param flag Default behavior is to disable ZWrite, i.e. false. */ + virtual void setAllowZWriteOnTransparent(bool flag) = 0; + }; + +} // end namespace video +} // end namespace irr + + +#endif + + + diff --git a/irrlicht_1.5_update/source/Irrlicht/COpenGLDriver.cpp b/irrlicht_1.5_update/source/Irrlicht/COpenGLDriver.cpp new file mode 100755 index 000000000..6b303db3a --- /dev/null +++ b/irrlicht_1.5_update/source/Irrlicht/COpenGLDriver.cpp @@ -0,0 +1,3121 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COpenGLDriver.h" +// needed here also because of the create methods' parameters +#include "CNullDriver.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "COpenGLTexture.h" +#include "COpenGLMaterialRenderer.h" +#include "COpenGLShaderMaterialRenderer.h" +#include "COpenGLSLMaterialRenderer.h" +#include "COpenGLNormalMapRenderer.h" +#include "COpenGLParallaxMapRenderer.h" +#include "CImage.h" +#include "os.h" + +#ifdef _IRR_USE_SDL_DEVICE_ +#include +#endif + +namespace irr +{ +namespace video +{ + +// ----------------------------------------------------------------------- +// WINDOWS CONSTRUCTOR +// ----------------------------------------------------------------------- +#ifdef _IRR_USE_WINDOWS_DEVICE_ +//! Windows constructor and init code +COpenGLDriver::COpenGLDriver(const irr::SIrrlichtCreationParameters& params, + io::IFileSystem* io) +: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), + CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), + AntiAlias(params.AntiAlias), RenderTargetTexture(0), LastSetLight(-1), + CurrentRendertargetSize(0,0), + HDc(0), Window(static_cast(params.WindowId)), HRc(0) +{ + #ifdef _DEBUG + setDebugName("COpenGLDriver"); + #endif +} + +//! inits the open gl driver +bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) +{ + // Set up ixel format descriptor with desired parameters + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + params.Bits, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // No Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 24, // Z-Buffer (Depth Buffer) + params.Stencilbuffer ? 1 : 0, // Stencil Buffer Depth + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + GLuint PixelFormat; + + if (AntiAlias) + { + // Create a window to test antialiasing support + const c8* ClassName = "GLCIrrDeviceWin32"; + HINSTANCE lhInstance = GetModuleHandle(0); + + // Register Class + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)DefWindowProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = lhInstance; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = 0; + wcex.lpszClassName = ClassName; + wcex.hIconSm = 0; + wcex.hIcon = 0; + + RegisterClassEx(&wcex); + RECT clientSize; + clientSize.top = 0; + clientSize.left = 0; + clientSize.right = params.WindowSize.Width; + clientSize.bottom = params.WindowSize.Height; + + DWORD style = WS_POPUP; + + if (!params.Fullscreen) + style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + + AdjustWindowRect(&clientSize, style, FALSE); + + const s32 realWidth = clientSize.right - clientSize.left; + const s32 realHeight = clientSize.bottom - clientSize.top; + + const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2; + const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2; + + HWND temporary_wnd=CreateWindow(ClassName, "", style, windowLeft, windowTop, + realWidth, realHeight, NULL, NULL, lhInstance, NULL); + + if(!temporary_wnd) + { + os::Printer::log("Cannot create a temporary window.", ELL_ERROR); + return false; + } + + HDc = GetDC(temporary_wnd); + for (u32 i=0; i<5; ++i) + { + if (i == 1) + { + if (params.Stencilbuffer) + { + os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING); + params.Stencilbuffer = false; + pfd.cStencilBits = 0; + } + else + continue; + } + else + if (i == 2) + { + pfd.cDepthBits = 24; + } + if (i == 3) + { + if (params.Bits!=16) + pfd.cDepthBits = 16; + else + continue; + } + else + if (i == 4) + { + os::Printer::log("Cannot create a GL device context", "No suitable format for temporary window.", ELL_ERROR); + ReleaseDC(temporary_wnd, HDc); + DestroyWindow(temporary_wnd); + return false; + } + + // choose pixelformat + PixelFormat = ChoosePixelFormat(HDc, &pfd); + if (PixelFormat) + break; + } + + SetPixelFormat(HDc, PixelFormat, &pfd); + HRc=wglCreateContext(HDc); + if(!HRc) + { + os::Printer::log("Cannot create a temporary GL rendering context.", ELL_ERROR); + ReleaseDC(temporary_wnd, HDc); + DestroyWindow(temporary_wnd); + return false; + } + + if(!wglMakeCurrent(HDc, HRc)) + { + os::Printer::log("Cannot activate a temporary GL rendering context.", ELL_ERROR); + wglDeleteContext(HRc); + ReleaseDC(temporary_wnd, HDc); + DestroyWindow(temporary_wnd); + return false; + } + + PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat_ARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); + if(wglChoosePixelFormat_ARB) + { + // This value determines the number of samples used for antialiasing + // valid numbers are 2, 4, 8. My experience is that 8 does not + // show a big improvement over 4, but 4 shows a big improvement over + // 2. + const s32 numSamples = 4; + f32 fAttributes[] = + { + 0.0, 0.0 + }; + + s32 iAttributes[] = + { + WGL_DRAW_TO_WINDOW_ARB,GL_TRUE, + WGL_SUPPORT_OPENGL_ARB,GL_TRUE, + WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB, + WGL_COLOR_BITS_ARB,(params.Bits==32) ? 24 : 15, + WGL_ALPHA_BITS_ARB,(params.Bits==32) ? 8 : 1, + WGL_DEPTH_BITS_ARB,params.ZBufferBits, + WGL_STENCIL_BITS_ARB,(params.Stencilbuffer) ? 1 : 0, + WGL_DOUBLE_BUFFER_ARB,GL_TRUE, + WGL_SAMPLE_BUFFERS_ARB,GL_TRUE, + WGL_SAMPLES_ARB,numSamples, + 0,0 + }; + s32 rv=0; + + // Try to get an acceptable pixel format + while(rv==0 && iAttributes[19]>1) + { + s32 pixelFormat=0; + u32 numFormats=0; + const s32 valid = wglChoosePixelFormat_ARB(HDc,iAttributes,fAttributes,1,&pixelFormat,&numFormats); + + if(valid && numFormats>0) + rv = pixelFormat; + else + iAttributes[19] >>= 1; + } + if(rv) + PixelFormat=rv; + } + + wglMakeCurrent(HDc, NULL); + wglDeleteContext(HRc); + ReleaseDC(temporary_wnd, HDc); + DestroyWindow(temporary_wnd); + } + + // get hdc + HDc=GetDC(Window); + if (!HDc) + { + os::Printer::log("Cannot create a GL device context.", ELL_ERROR); + return false; + } + + // search for pixel format the simple way + if (!AntiAlias) + { + for (u32 i=0; i<5; ++i) + { + if (i == 1) + { + if (params.Stencilbuffer) + { + os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING); + params.Stencilbuffer = false; + pfd.cStencilBits = 0; + } + else + continue; + } + else + if (i == 2) + { + pfd.cDepthBits = 24; + } + if (i == 3) + { + if (params.Bits!=16) + pfd.cDepthBits = 16; + else + continue; + } + else + if (i == 4) + { + os::Printer::log("Cannot create a GL device context", "No suitable format.", ELL_ERROR); + return false; + } + + // choose pixelformat + PixelFormat = ChoosePixelFormat(HDc, &pfd); + if (PixelFormat) + break; + } + } + + // set pixel format + if(!SetPixelFormat(HDc, PixelFormat, &pfd)) + { + os::Printer::log("Cannot set the pixel format.", ELL_ERROR); + return false; + } + + // create rendering context + HRc=wglCreateContext(HDc); + if (!HRc) + { + os::Printer::log("Cannot create a GL rendering context.", ELL_ERROR); + return false; + } + + // activate rendering context + if(!wglMakeCurrent(HDc, HRc)) + { + os::Printer::log("Cannot activate GL rendering context", ELL_ERROR); + wglDeleteContext(HRc); + return false; + } + + int pf = GetPixelFormat(HDc); + DescribePixelFormat(HDc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + if (pfd.cAlphaBits != 0) + { + if (pfd.cRedBits == 8) + ColorFormat = ECF_A8R8G8B8; + else + ColorFormat = ECF_A1R5G5B5; + } + else + { + if (pfd.cRedBits == 8) + ColorFormat = ECF_R8G8B8; + else + ColorFormat = ECF_R5G6B5; + } + + genericDriverInit(params.WindowSize, params.Stencilbuffer); + + // set vsync + if (wglSwapIntervalEXT) + wglSwapIntervalEXT(params.Vsync ? 1 : 0); + + // set exposed data + ExposedData.OpenGLWin32.HDc = HDc; + ExposedData.OpenGLWin32.HRc = HRc; + ExposedData.OpenGLWin32.HWnd = Window; + + return true; +} + +#endif //IRR_USE_WINDOWS_DEVICE_ + +// ----------------------------------------------------------------------- +// MacOSX CONSTRUCTOR +// ----------------------------------------------------------------------- +#ifdef _IRR_USE_OSX_DEVICE_ +//! Windows constructor and init code +COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceMacOSX *device) +: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), + CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), + AntiAlias(params.AntiAlias), RenderTargetTexture(0), LastSetLight(-1), + CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), _device(device) +{ + #ifdef _DEBUG + setDebugName("COpenGLDriver"); + #endif + genericDriverInit(params.WindowSize, params.Stencilbuffer); +} + +#endif + +// ----------------------------------------------------------------------- +// LINUX CONSTRUCTOR +// ----------------------------------------------------------------------- +#ifdef _IRR_USE_LINUX_DEVICE_ +//! Linux constructor and init code +COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io) +: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), + CurrentRenderMode(ERM_NONE), ResetRenderStates(true), + Transformation3DChanged(true), AntiAlias(params.AntiAlias), + RenderTargetTexture(0), LastSetLight(-1), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8) +{ + #ifdef _DEBUG + setDebugName("COpenGLDriver"); + #endif + ExposedData.OpenGLLinux.X11Context = glXGetCurrentContext(); + ExposedData.OpenGLLinux.X11Display = glXGetCurrentDisplay(); + ExposedData.OpenGLLinux.X11Window = (unsigned long)params.WindowId; + Drawable = glXGetCurrentDrawable(); + + genericDriverInit(params.WindowSize, params.Stencilbuffer); + + // set vsync +#ifdef GLX_SGI_swap_control +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (params.Vsync && glxSwapIntervalSGI) + glxSwapIntervalSGI(1); +#else + if (params.Vsync) + glXSwapIntervalSGI(1); +#endif +#endif +} + +#endif // _IRR_USE_LINUX_DEVICE_ + + +// ----------------------------------------------------------------------- +// SDL CONSTRUCTOR +// ----------------------------------------------------------------------- +#ifdef _IRR_USE_SDL_DEVICE_ +//! SDL constructor and init code +COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io) +: CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), + CurrentRenderMode(ERM_NONE), ResetRenderStates(true), + Transformation3DChanged(true), AntiAlias(params.AntiAlias), + RenderTargetTexture(0), LastSetLight(-1), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8) +{ + #ifdef _DEBUG + setDebugName("COpenGLDriver"); + #endif + + genericDriverInit(params.WindowSize, params.Stencilbuffer); +} + +#endif // _IRR_USE_SDL_DEVICE_ + + +//! destructor +COpenGLDriver::~COpenGLDriver() +{ + deleteMaterialRenders(); + + // I get a blue screen on my laptop, when I do not delete the + // textures manually before releasing the dc. Oh how I love this. + + deleteAllTextures(); + +#ifdef _IRR_USE_WINDOWS_DEVICE_ + if (HRc) + { + if (!wglMakeCurrent(0, 0)) + os::Printer::log("Release of dc and rc failed.", ELL_WARNING); + + if (!wglDeleteContext(HRc)) + os::Printer::log("Release of rendering context failed.", ELL_WARNING); + } + + if (HDc) + ReleaseDC(Window, HDc); +#endif +} + +// ----------------------------------------------------------------------- +// METHODS +// ----------------------------------------------------------------------- + +bool COpenGLDriver::genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer) +{ + Name=L"OpenGL "; + Name.append(glGetString(GL_VERSION)); + s32 pos=Name.findNext(L' ', 7); + if (pos != -1) + Name=Name.subString(0, pos); + printVersion(); + + // print renderer information + const GLubyte* renderer = glGetString(GL_RENDERER); + const GLubyte* vendor = glGetString(GL_VENDOR); + if (renderer && vendor) + { + os::Printer::log(reinterpret_cast(renderer), reinterpret_cast(vendor), ELL_INFORMATION); + vendorName = reinterpret_cast(vendor); + } + + u32 i; + for (i=0; i101) || FeatureAvailable[IRR_EXT_rescale_normal]) +// glEnable(GL_RESCALE_NORMAL_EXT); + + glClearDepth(1.0); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glDepthFunc(GL_LEQUAL); + glFrontFace( GL_CW ); + + if (AntiAlias) + { + if (MultiSamplingExtension) + glEnable(GL_MULTISAMPLE_ARB); + + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glEnable(GL_LINE_SMOOTH); + } +// currently disabled, because often in software, and thus very slow +// glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST); +// glEnable(GL_POINT_SMOOTH); + + UserClipPlane.reallocate(MaxUserClipPlanes); + UserClipPlaneEnabled.reallocate(MaxUserClipPlanes); + for (i=0; idrop(); + + // add remaining material renderer + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_DETAIL_MAP(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SPHERE_MAP(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_REFLECTION_2_LAYER(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(this)); + + // add normal map renderers + s32 tmp = 0; + video::IMaterialRenderer* renderer = 0; + renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_SOLID].Renderer); + renderer->drop(); + renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); + renderer->drop(); + renderer = new COpenGLNormalMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); + renderer->drop(); + + // add parallax map renderers + renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_SOLID].Renderer); + renderer->drop(); + renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); + renderer->drop(); + renderer = new COpenGLParallaxMapRenderer(this, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); + renderer->drop(); + + // add basic 1 texture blending + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_ONETEXTURE_BLEND(this)); +} + + +//! presents the rendered scene on the screen, returns false if failed +bool COpenGLDriver::endScene() +{ + CNullDriver::endScene(); + + glFlush(); + +#ifdef _IRR_USE_WINDOWS_DEVICE_ + return SwapBuffers(HDc) == TRUE; +#elif defined(_IRR_USE_LINUX_DEVICE_) + glXSwapBuffers((Display*)ExposedData.OpenGLLinux.X11Display, Drawable); + return true; +#elif defined(_IRR_USE_OSX_DEVICE_) + _device->flush(); + return true; +#elif defined(_IRR_USE_SDL_DEVICE_) + SDL_GL_SwapBuffers(); + return true; +#else + return false; +#endif +} + + +//! clears the zbuffer +bool COpenGLDriver::beginScene(bool backBuffer, bool zBuffer, SColor color, + void* windowId, core::rect* sourceRect) +{ + CNullDriver::beginScene(backBuffer, zBuffer, color, windowId, sourceRect); + + GLbitfield mask = 0; + + if (backBuffer) + { + const f32 inv = 1.0f / 255.0f; + glClearColor(color.getRed() * inv, color.getGreen() * inv, + color.getBlue() * inv, color.getAlpha() * inv); + + mask |= GL_COLOR_BUFFER_BIT; + } + + if (zBuffer) + { + glDepthMask(GL_TRUE); + LastMaterial.ZWriteEnable=true; + mask |= GL_DEPTH_BUFFER_BIT; + } + + glClear(mask); + return true; +} + + +//! Returns the transformation set by setTransform +const core::matrix4& COpenGLDriver::getTransform(E_TRANSFORMATION_STATE state) const +{ + return Matrices[state]; +} + + +//! sets transformation +void COpenGLDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) +{ + Matrices[state] = mat; + Transformation3DChanged = true; + + switch(state) + { + case ETS_VIEW: + case ETS_WORLD: + { + // OpenGL only has a model matrix, view and world is not existent. so lets fake these two. + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer()); + // we have to update the clip planes to the latest view matrix + for (u32 i=0; iisRenderTarget(); + + if (MultiTextureExtension) + extGlActiveTexture(GL_TEXTURE0_ARB + i); + + glMatrixMode(GL_TEXTURE); + if (mat.isIdentity() && !isRTT) + glLoadIdentity(); + else + { + GLfloat glmat[16]; + if (isRTT) + createGLTextureMatrix(glmat, mat * TextureFlipMatrix); + else + createGLTextureMatrix(glmat, mat); + + glLoadMatrixf(glmat); + } + break; + } + default: + break; + } +} + +bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) +{ + if (!HWBuffer) + return false; + + if (!FeatureAvailable[IRR_ARB_vertex_buffer_object]) + return false; + +#if defined(GL_ARB_vertex_buffer_object) + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + const void* vertices=mb->getVertices(); + const u32 vertexCount=mb->getVertexCount(); + const E_VERTEX_TYPE vType=mb->getVertexType(); + const u32 vertexSize = getVertexPitchFromType(vType); + + //buffer vertex data, and convert colours... + core::array buffer(vertexSize * vertexCount); + memcpy(buffer.pointer(), vertices, vertexSize * vertexCount); + + // in order to convert the colors into opengl format (RGBA) + switch (vType) + { + case EVT_STANDARD: + { + S3DVertex* pb = reinterpret_cast(buffer.pointer()); + const S3DVertex* po = static_cast(vertices); + for (u32 i=0; i(buffer.pointer()); + const S3DVertex2TCoords* po = static_cast(vertices); + for (u32 i=0; i(buffer.pointer()); + const S3DVertexTangents* po = static_cast(vertices); + for (u32 i=0; ivbo_verticesID) + { + extGlGenBuffers(1, &HWBuffer->vbo_verticesID); + if (!HWBuffer->vbo_verticesID) return false; + newBuffer=true; + } + else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize) + { + newBuffer=true; + } + + extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID ); + + //copy data to graphics card + glGetError(); // clear error storage + if (!newBuffer) + extGlBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, buffer.const_pointer()); + else + { + HWBuffer->vbo_verticesSize = vertexCount*vertexSize; + + if (HWBuffer->Mapped_Vertex==scene::EHM_STATIC) + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_STATIC_DRAW); + else if (HWBuffer->Mapped_Vertex==scene::EHM_DYNAMIC) + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_DYNAMIC_DRAW); + else //scene::EHM_STREAM + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_STREAM_DRAW); + } + + extGlBindBuffer(GL_ARRAY_BUFFER, 0); + + return (glGetError() == GL_NO_ERROR); +#else + return false; +#endif +} + + +bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) +{ + if (!HWBuffer) + return false; + + if(!FeatureAvailable[IRR_ARB_vertex_buffer_object]) + return false; + +#if defined(GL_ARB_vertex_buffer_object) + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + + const void* indices=mb->getIndices(); + u32 indexCount= mb->getIndexCount(); + + GLenum indexSize; + switch (mb->getIndexType()) + { + case (EIT_16BIT): + { + indexSize=sizeof(u16); + break; + } + case (EIT_32BIT): + { + indexSize=sizeof(u32); + break; + } + default: + { + return false; + } + } + + + //get or create buffer + bool newBuffer=false; + if (!HWBuffer->vbo_indicesID) + { + extGlGenBuffers(1, &HWBuffer->vbo_indicesID); + if (!HWBuffer->vbo_indicesID) return false; + newBuffer=true; + } + else if (HWBuffer->vbo_indicesSize < indexCount*indexSize) + { + newBuffer=true; + } + + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + + //copy data to graphics card + glGetError(); // clear error storage + if (!newBuffer) + extGlBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices); + else + { + HWBuffer->vbo_indicesSize = indexCount*indexSize; + + if (HWBuffer->Mapped_Index==scene::EHM_STATIC) + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW); + else if (HWBuffer->Mapped_Index==scene::EHM_DYNAMIC) + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW); + else //scene::EHM_STREAM + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STREAM_DRAW); + } + + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + return (glGetError() == GL_NO_ERROR); +#else + return false; +#endif +} + + +//! updates hardware buffer if needed +bool COpenGLDriver::updateHardwareBuffer(SHWBufferLink *HWBuffer) +{ + if (!HWBuffer) + return false; + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex() + || !((SHWBufferLink_opengl*)HWBuffer)->vbo_verticesID) + { + + HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex(); + + if (!updateVertexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer)) + return false; + } + } + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index() + || !((SHWBufferLink_opengl*)HWBuffer)->vbo_indicesID) + { + + HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index(); + + if (!updateIndexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer)) + return false; + } + } + + return true; +} + + +//! Create hardware buffer from meshbuffer +COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::IMeshBuffer* mb) +{ +#if defined(GL_ARB_vertex_buffer_object) + if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER)) + return 0; + + SHWBufferLink_opengl *HWBuffer=new SHWBufferLink_opengl(mb); + + //add to map + HWBufferMap.insert(HWBuffer->MeshBuffer, HWBuffer); + + HWBuffer->ChangedID_Vertex=HWBuffer->MeshBuffer->getChangedID_Vertex(); + HWBuffer->ChangedID_Index=HWBuffer->MeshBuffer->getChangedID_Index(); + HWBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex(); + HWBuffer->Mapped_Index=mb->getHardwareMappingHint_Index(); + HWBuffer->LastUsed=0; + HWBuffer->vbo_verticesID=0; + HWBuffer->vbo_indicesID=0; + HWBuffer->vbo_verticesSize=0; + HWBuffer->vbo_indicesSize=0; + + if (!updateHardwareBuffer(HWBuffer)) + { + deleteHardwareBuffer(HWBuffer); + return 0; + } + + return HWBuffer; +#else + return 0; +#endif +} + + +void COpenGLDriver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) return; + + +#if defined(GL_ARB_vertex_buffer_object) + SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; + if (HWBuffer->vbo_verticesID) + { + extGlDeleteBuffers(1, &HWBuffer->vbo_verticesID); + HWBuffer->vbo_verticesID=0; + } + if (HWBuffer->vbo_indicesID) + { + extGlDeleteBuffers(1, &HWBuffer->vbo_indicesID); + HWBuffer->vbo_indicesID=0; + } +#endif + + CNullDriver::deleteHardwareBuffer(_HWBuffer); + +} + + +//! Draw hardware buffer +void COpenGLDriver::drawHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) + return; + + SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; + + updateHardwareBuffer(HWBuffer); //check if update is needed + + HWBuffer->LastUsed=0;//reset count + +#if defined(GL_ARB_vertex_buffer_object) + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + + + const void *vertices=mb->getVertices(); + const void *indexList=mb->getIndices(); + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + { + extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); + vertices=0; + } + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + { + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + indexList=0; + } + + + drawVertexPrimitiveList(vertices, mb->getVertexCount(), indexList, mb->getIndexCount()/3, mb->getVertexType(), scene::EPT_TRIANGLES, mb->getIndexType()); + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + extGlBindBuffer(GL_ARRAY_BUFFER, 0); + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + + +#endif +} + + +// small helper function to create vertex buffer object adress offsets +static inline u8* buffer_offset(const long offset) +{ + return ((u8*)0 + offset); +} + + +//! draws a vertex primitive list +void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + if (!primitiveCount || !vertexCount) + return; + + if (!checkPrimitiveCount(primitiveCount)) + return; + + CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); + + if (vertices) + { + // convert colors to gl color format. + vertexCount *= 4; //reused as color component count + ColorBuffer.set_used(vertexCount); + u32 i; + + switch (vType) + { + case EVT_STANDARD: + { + const S3DVertex* p = static_cast(vertices); + for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + case EVT_2TCOORDS: + { + const S3DVertex2TCoords* p = static_cast(vertices); + for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + case EVT_TANGENTS: + { + const S3DVertexTangents* p = static_cast(vertices); + for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + } + } + + // draw everything + setRenderStates3DMode(); + + if (MultiTextureExtension) + extGlClientActiveTexture(GL_TEXTURE0_ARB); + + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) + glEnableClientState(GL_NORMAL_ARRAY); + + if (vertices) + glColorPointer(4, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + + switch (vType) + { + case EVT_STANDARD: + if (vertices) + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex), buffer_offset(12)); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), 0); + } + + if (MultiTextureExtension && CurrentTexture[1]) + { + extGlClientActiveTexture(GL_TEXTURE1_ARB); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + } + break; + case EVT_2TCOORDS: + if (vertices) + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(12)); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0)); + } + + + if (MultiTextureExtension) + { + extGlClientActiveTexture(GL_TEXTURE1_ARB); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords2); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36)); + } + break; + case EVT_TANGENTS: + if (vertices) + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].TCoords); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(12)); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0)); + } + + if (MultiTextureExtension) + { + extGlClientActiveTexture(GL_TEXTURE1_ARB); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Tangent); + else + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36)); + + extGlClientActiveTexture(GL_TEXTURE2_ARB); + glEnableClientState ( GL_TEXTURE_COORD_ARRAY ); + if (vertices) + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Binormal); + else + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48)); + } + break; + } + + GLenum indexSize=0; + + switch (iType) + { + case (EIT_16BIT): + { + indexSize=GL_UNSIGNED_SHORT; + break; + } + case (EIT_32BIT): + { + indexSize=GL_UNSIGNED_INT; + break; + } + } + + switch (pType) + { + case scene::EPT_POINTS: + case scene::EPT_POINT_SPRITES: + { +#ifdef GL_ARB_point_sprite + if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) + glEnable(GL_POINT_SPRITE_ARB); +#endif + float quadratic[] = {0.0f, 0.0f, 10.01f}; + extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION_ARB, quadratic); + float maxParticleSize=1.0f; + glGetFloatv(GL_POINT_SIZE_MAX_ARB, &maxParticleSize); +// maxParticleSize=maxParticleSize &vertices, + const core::array *colors, + const video::ITexture *texture, + bool useAlphaChannelOfTexture, + const core::array *coordinates) +{ + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture && texture->isRenderTarget(); + core::array tex_coordinates; + if(texture) + { + const core::dimension2d& ss = texture->getOriginalSize(); + const f32 height = static_cast(ss.Height); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + for(u32 i=0; i<(*coordinates).size(); i++) + { + core::vector2df t( (*coordinates)[i].X * invW, + (isRTT?height-(*coordinates)[i].Y:(*coordinates)[i].Y)*invH); + tex_coordinates.push_back(t); + } + } // if texture + disableTextures(1); + if(texture) + setTexture(0, texture); + bool doAlpha = colors!=NULL; + setRenderStates2DMode(doAlpha, texture!=NULL, useAlphaChannelOfTexture); + // Some obvious optimisation. + if(vertices.size()==3) + glBegin(GL_TRIANGLES); + else if(vertices.size()==4) + glBegin(GL_QUADS); + else + glBegin(GL_POLYGON); + for (u32 i=0; isize() ? (*colors)[i] : (*colors)[0]; + glColor4ub(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + } + if(texture) + glTexCoord2f(tex_coordinates[i].X, tex_coordinates[i].Y); + + glVertex2f(GLfloat(vertices[i].X), GLfloat(vertices[i].Y)); + } + glEnd(); + +} // draw2DPolygon + + + +//! draws a 2d image, using a color and the alpha channel of the texture if +//! desired. The image is drawn at pos, clipped against clipRect (if != 0). +//! Only the subtexture defined by sourceRect is used. +void COpenGLDriver::draw2DImage(const video::ITexture* texture, + const core::position2d& pos, + const core::rect& sourceRect, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + if (!sourceRect.isValid()) + return; + + core::position2d targetPos(pos); + core::position2d sourcePos(sourceRect.UpperLeftCorner); + core::dimension2d sourceSize(sourceRect.getSize()); + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + return; + } + } + + // clip these coordinates + + if (targetPos.X<0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (targetPos.X + sourceSize.Width > renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y<0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + return; + } + + // ok, we've clipped everything. + // now draw it. + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const core::dimension2d& ss = texture->getOriginalSize(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + const core::rect tcoords( + sourcePos.X * invW, + (isRTT?(sourcePos.Y + sourceSize.Height):sourcePos.Y) * invH, + (sourcePos.X + sourceSize.Width) * invW, + (isRTT?sourcePos.Y:(sourcePos.Y + sourceSize.Height)) * invH); + + const core::rect poss(targetPos, sourceSize); + + disableTextures(1); + if (!setTexture(0, texture)) + return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glBegin(GL_QUADS); + + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.UpperLeftCorner.Y)); + + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.UpperLeftCorner.Y)); + + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.LowerRightCorner.Y)); + + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.LowerRightCorner.Y)); + + glEnd(); +} + + +//! The same, but with a four element array of colors, one for each vertex +void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect, + const video::SColor* const colors, bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const core::dimension2d& ss = texture->getOriginalSize(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + const core::rect tcoords( + sourceRect.UpperLeftCorner.X * invW, + (isRTT?sourceRect.LowerRightCorner.Y:sourceRect.UpperLeftCorner.Y) * invH, + sourceRect.LowerRightCorner.X * invW, + (isRTT?sourceRect.UpperLeftCorner.Y:sourceRect.LowerRightCorner.Y) *invH); + + const video::SColor temp[4] = + { + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF + }; + + const video::SColor* const useColor = colors ? colors : temp; + + disableTextures(1); + setTexture(0, texture); + setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 || + useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255, + true, useAlphaChannelOfTexture); + + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, + clipRect->getWidth(), clipRect->getHeight()); + } + + glBegin(GL_QUADS); + + glColor4ub(useColor[0].getRed(), useColor[0].getGreen(), useColor[0].getBlue(), useColor[0].getAlpha()); + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(destRect.UpperLeftCorner.X), GLfloat(destRect.UpperLeftCorner.Y)); + + glColor4ub(useColor[3].getRed(), useColor[3].getGreen(), useColor[3].getBlue(), useColor[3].getAlpha()); + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(destRect.LowerRightCorner.X), GLfloat(destRect.UpperLeftCorner.Y)); + + glColor4ub(useColor[2].getRed(), useColor[2].getGreen(), useColor[2].getBlue(), useColor[2].getAlpha()); + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(destRect.LowerRightCorner.X), GLfloat(destRect.LowerRightCorner.Y)); + + glColor4ub(useColor[1].getRed(), useColor[1].getGreen(), useColor[1].getBlue(), useColor[1].getAlpha()); + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(destRect.UpperLeftCorner.X), GLfloat(destRect.LowerRightCorner.Y)); + + glEnd(); + + if (clipRect) + glDisable(GL_SCISSOR_TEST); +} + + +//! draws a set of 2d images, using a color and the alpha channel of the +//! texture if desired. The images are drawn beginning at pos and concatenated +//! in one line. All drawings are clipped against clipRect (if != 0). +//! The subtextures are defined by the array of sourceRects and are chosen +//! by the indices given. +void COpenGLDriver::draw2DImage(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + disableTextures(1); + if (!setTexture(0, texture)) + return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, + clipRect->getWidth(),clipRect->getHeight()); + } + + const core::dimension2d& ss = texture->getOriginalSize(); + core::position2d targetPos(pos); + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + + for (u32 i=0; i tcoords( + sourceRects[currentIndex].UpperLeftCorner.X * invW, + (isRTT?sourceRects[currentIndex].LowerRightCorner.Y:sourceRects[currentIndex].UpperLeftCorner.Y) * invH, + sourceRects[currentIndex].LowerRightCorner.X * invW, + (isRTT?sourceRects[currentIndex].UpperLeftCorner.Y:sourceRects[currentIndex].LowerRightCorner.Y) * invH); + + const core::rect poss(targetPos, sourceRects[currentIndex].getSize()); + + glBegin(GL_QUADS); + + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.UpperLeftCorner.Y)); + + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.UpperLeftCorner.Y)); + + glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(poss.LowerRightCorner.X), GLfloat(poss.LowerRightCorner.Y)); + + glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + glVertex2f(GLfloat(poss.UpperLeftCorner.X), GLfloat(poss.LowerRightCorner.Y)); + + glEnd(); + targetPos.X += sourceRects[currentIndex].getWidth(); + } + if (clipRect) + glDisable(GL_SCISSOR_TEST); +} + + +//! draw a 2d rectangle +void COpenGLDriver::draw2DRectangle(SColor color, const core::rect& position, + const core::rect* clip) +{ + disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glRectf(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.UpperLeftCorner.Y), + GLfloat(pos.LowerRightCorner.X), GLfloat(pos.LowerRightCorner.Y)); +} + + +//! draw an 2d rectangle +void COpenGLDriver::draw2DRectangle(const core::rect& position, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) +{ + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + disableTextures(); + + setRenderStates2DMode(colorLeftUp.getAlpha() < 255 || + colorRightUp.getAlpha() < 255 || + colorLeftDown.getAlpha() < 255 || + colorRightDown.getAlpha() < 255, false, false); + + glBegin(GL_QUADS); + glColor4ub(colorLeftUp.getRed(), colorLeftUp.getGreen(), + colorLeftUp.getBlue(), colorLeftUp.getAlpha()); + glVertex2f(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.UpperLeftCorner.Y)); + + glColor4ub(colorRightUp.getRed(), colorRightUp.getGreen(), + colorRightUp.getBlue(), colorRightUp.getAlpha()); + glVertex2f(GLfloat(pos.LowerRightCorner.X), GLfloat(pos.UpperLeftCorner.Y)); + + glColor4ub(colorRightDown.getRed(), colorRightDown.getGreen(), + colorRightDown.getBlue(), colorRightDown.getAlpha()); + glVertex2f(GLfloat(pos.LowerRightCorner.X), GLfloat(pos.LowerRightCorner.Y)); + + glColor4ub(colorLeftDown.getRed(), colorLeftDown.getGreen(), + colorLeftDown.getBlue(), colorLeftDown.getAlpha()); + glVertex2f(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.LowerRightCorner.Y)); + + glEnd(); +} + + +//! Draws a 2d line. +void COpenGLDriver::draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color) +{ + disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + glBegin(GL_LINES); + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glVertex2f(GLfloat(start.X), GLfloat(start.Y)); + glVertex2f(GLfloat(end.X), GLfloat(end.Y)); + glEnd(); +} + +//! Draws a pixel +void COpenGLDriver::drawPixel(u32 x, u32 y, const SColor &color) +{ + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + if(x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) + return; + + disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + glBegin(GL_POINTS); + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glVertex2i(x, y); + glEnd(); +} + +bool COpenGLDriver::setTexture(u32 stage, const video::ITexture* texture) +{ + if (stage >= MaxTextureUnits) + return false; + + if (CurrentTexture[stage]==texture) + return true; + + if (MultiTextureExtension) + extGlActiveTexture(GL_TEXTURE0_ARB + stage); + + CurrentTexture[stage]=texture; + + if (!texture) + { + glDisable(GL_TEXTURE_2D); + return true; + } + else + { + if (texture->getDriverType() != EDT_OPENGL) + { + glDisable(GL_TEXTURE_2D); + os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); + return false; + } + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, + static_cast(texture)->getOpenGLTextureName()); + } + return true; +} + + +//! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled. +//! Returns whether disabling was successful or not. +bool COpenGLDriver::disableTextures(u32 fromStage) +{ + bool result=true; + for (u32 i=fromStage; i= 0; --i) + { + setTransform ((E_TRANSFORMATION_STATE) ( ETS_TEXTURE_0 + i ), + material.getTextureMatrix(i)); + } +} + + +//! prints error if an error happened. +bool COpenGLDriver::testGLError() +{ +#ifdef _DEBUG + GLenum g = glGetError(); + switch(g) + { + case GL_NO_ERROR: + return false; + case GL_INVALID_ENUM: + os::Printer::log("GL_INVALID_ENUM", ELL_ERROR); break; + case GL_INVALID_VALUE: + os::Printer::log("GL_INVALID_VALUE", ELL_ERROR); break; + case GL_INVALID_OPERATION: + os::Printer::log("GL_INVALID_OPERATION", ELL_ERROR); break; + case GL_STACK_OVERFLOW: + os::Printer::log("GL_STACK_OVERFLOW", ELL_ERROR); break; + case GL_STACK_UNDERFLOW: + os::Printer::log("GL_STACK_UNDERFLOW", ELL_ERROR); break; + case GL_OUT_OF_MEMORY: + os::Printer::log("GL_OUT_OF_MEMORY", ELL_ERROR); break; + case GL_TABLE_TOO_LARGE: + os::Printer::log("GL_TABLE_TOO_LARGE", ELL_ERROR); break; +#if defined(GL_EXT_framebuffer_object) + case GL_INVALID_FRAMEBUFFER_OPERATION_EXT: + os::Printer::log("GL_INVALID_FRAMEBUFFER_OPERATION", ELL_ERROR); break; +#endif + }; + return true; +#else + return false; +#endif +} + + +//! sets the needed renderstates +void COpenGLDriver::setRenderStates3DMode() +{ + if (CurrentRenderMode != ERM_3D) + { + // Reset Texture Stages + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); + + // switch back the matrices + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer()); + + GLfloat glmat[16]; + createGLMatrix(glmat, Matrices[ETS_PROJECTION]); + glmat[12] *= -1.0f; + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(glmat); + + ResetRenderStates = true; + } + + if ( ResetRenderStates || LastMaterial != Material) + { + // unset old material + + if (LastMaterial.MaterialType != Material.MaterialType && + static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + + // set new material. + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial( + Material, LastMaterial, ResetRenderStates, this); + + LastMaterial = Material; + ResetRenderStates = false; + } + + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD); + + CurrentRenderMode = ERM_3D; +} + + +void COpenGLDriver::setWrapMode(const SMaterial& material) +{ + // texture address mode + // Has to be checked always because it depends on the textures + for (u32 u=0; u0) + break; // stop loop + + GLint mode=GL_REPEAT; + switch (material.TextureLayer[u].TextureWrap) + { + case ETC_REPEAT: + mode=GL_REPEAT; + break; + case ETC_CLAMP: + mode=GL_CLAMP; + break; + case ETC_CLAMP_TO_EDGE: +#ifdef GL_VERSION_1_2 + if (Version>101) + mode=GL_CLAMP_TO_EDGE; + else +#endif +#ifdef GL_SGIS_texture_edge_clamp + if (FeatureAvailable[IRR_SGIS_texture_edge_clamp]) + mode=GL_CLAMP_TO_EDGE_SGIS; + else +#endif + // fallback + mode=GL_CLAMP; + break; + case ETC_CLAMP_TO_BORDER: +#ifdef GL_VERSION_1_3 + if (Version>102) + mode=GL_CLAMP_TO_BORDER; + else +#endif +#ifdef GL_ARB_texture_border_clamp + if (FeatureAvailable[IRR_ARB_texture_border_clamp]) + mode=GL_CLAMP_TO_BORDER_ARB; + else +#endif +#ifdef GL_SGIS_texture_border_clamp + if (FeatureAvailable[IRR_SGIS_texture_border_clamp]) + mode=GL_CLAMP_TO_BORDER_SGIS; + else +#endif + // fallback + mode=GL_CLAMP; + break; + case ETC_MIRROR: +#ifdef GL_VERSION_1_4 + if (Version>103) + mode=GL_MIRRORED_REPEAT; + else +#endif +#ifdef GL_ARB_texture_border_clamp + if (FeatureAvailable[IRR_ARB_texture_mirrored_repeat]) + mode=GL_MIRRORED_REPEAT_ARB; + else +#endif +#ifdef GL_IBM_texture_mirrored_repeat + if (FeatureAvailable[IRR_IBM_texture_mirrored_repeat]) + mode=GL_MIRRORED_REPEAT_IBM; + else +#endif + mode=GL_REPEAT; + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode); + } +} + + +//! Can be called by an IMaterialRenderer to make its work easier. +void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderStates) +{ + if (resetAllRenderStates || + lastmaterial.AmbientColor != material.AmbientColor || + lastmaterial.DiffuseColor != material.DiffuseColor || + lastmaterial.SpecularColor != material.SpecularColor || + lastmaterial.EmissiveColor != material.EmissiveColor || + lastmaterial.Shininess != material.Shininess) + { + GLfloat color[4]; + + const f32 inv = 1.0f / 255.0f; + + color[0] = material.AmbientColor.getRed() * inv; + color[1] = material.AmbientColor.getGreen() * inv; + color[2] = material.AmbientColor.getBlue() * inv; + color[3] = material.AmbientColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color); + + color[0] = material.DiffuseColor.getRed() * inv; + color[1] = material.DiffuseColor.getGreen() * inv; + color[2] = material.DiffuseColor.getBlue() * inv; + color[3] = material.DiffuseColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color); + + // disable Specular colors if no shininess is set + if (material.Shininess != 0.0f) + { +#ifdef GL_EXT_separate_specular_color + if (FeatureAvailable[IRR_EXT_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); +#endif + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess); + color[0] = material.SpecularColor.getRed() * inv; + color[1] = material.SpecularColor.getGreen() * inv; + color[2] = material.SpecularColor.getBlue() * inv; + color[3] = material.SpecularColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); + } +#ifdef GL_EXT_separate_specular_color + else + if (FeatureAvailable[IRR_EXT_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); +#endif + + color[0] = material.EmissiveColor.getRed() * inv; + color[1] = material.EmissiveColor.getGreen() * inv; + color[2] = material.EmissiveColor.getBlue() * inv; + color[3] = material.EmissiveColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color); + } + + // Texture filter + // Has to be checked always because it depends on the textures + // Filtering has to be set for each texture layer + for (u32 i=0; i0) + break; + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + + if (material.getTexture(i) && material.getTexture(i)->hasMipMaps()) + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR : + material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST : + GL_NEAREST_MIPMAP_NEAREST ); + else + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + +#ifdef GL_EXT_texture_filter_anisotropic + if (AnisotropyExtension) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, + material.TextureLayer[i].AnisotropicFilter ? MaxAnisotropy : 1.0f ); +#endif + } + + // fillmode + if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud)) + glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL); + + // shademode + if (resetAllRenderStates || (lastmaterial.GouraudShading != material.GouraudShading)) + { + if (material.GouraudShading) + glShadeModel(GL_SMOOTH); + else + glShadeModel(GL_FLAT); + } + + // lighting + if (resetAllRenderStates || (lastmaterial.Lighting != material.Lighting)) + { + if (material.Lighting) + glEnable(GL_LIGHTING); + else + glDisable(GL_LIGHTING); + } + + // zbuffer + if (resetAllRenderStates || lastmaterial.ZBuffer != material.ZBuffer) + { + switch (material.ZBuffer) + { + case 0: + glDisable(GL_DEPTH_TEST); + break; + case 1: + glEnable(GL_DEPTH_TEST); + glDepthFunc ( GL_LEQUAL ); + break; + case 2: + glEnable(GL_DEPTH_TEST); + glDepthFunc ( GL_EQUAL ); + break; + } + } + + // zwrite +// if (resetAllRenderStates || lastmaterial.ZWriteEnable != material.ZWriteEnable) + { + if (material.ZWriteEnable && (AllowZWriteOnTransparent || !material.isTransparent())) + { + glDepthMask(GL_TRUE); + } + else + glDepthMask(GL_FALSE); + } + + // back face culling + if (resetAllRenderStates || (lastmaterial.FrontfaceCulling != material.FrontfaceCulling) || (lastmaterial.BackfaceCulling != material.BackfaceCulling)) + { + if ((material.FrontfaceCulling) && (material.BackfaceCulling)) + { + glCullFace(GL_FRONT_AND_BACK); + glEnable(GL_CULL_FACE); + } + else + if (material.BackfaceCulling) + { + glCullFace(GL_BACK); + glEnable(GL_CULL_FACE); + } + else + if (material.FrontfaceCulling) + { + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + } + else + glDisable(GL_CULL_FACE); + } + + // fog + if (resetAllRenderStates || lastmaterial.FogEnable != material.FogEnable) + { + if (material.FogEnable) + glEnable(GL_FOG); + else + glDisable(GL_FOG); + } + + // normalization + if (resetAllRenderStates || lastmaterial.NormalizeNormals != material.NormalizeNormals) + { + if (material.NormalizeNormals) + glEnable(GL_NORMALIZE); + else + glDisable(GL_NORMALIZE); + } + + // thickness + if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness) + { + glPointSize(material.Thickness); + glLineWidth(material.Thickness); + } + + setWrapMode(material); + + // be sure to leave in texture stage 0 + if (MultiTextureExtension) + extGlActiveTexture(GL_TEXTURE0_ARB); +} + + +//! sets the needed renderstates +void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel) +{ + if (CurrentRenderMode != ERM_2D || Transformation3DChanged) + { + // unset last 3d material + if (CurrentRenderMode == ERM_3D) + { + if (static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + SMaterial mat; + mat.ZBuffer=0; + mat.Lighting=false; + mat.TextureLayer[0].BilinearFilter=false; + setBasicRenderStates(mat, mat, true); + LastMaterial = mat; + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + glMatrixMode(GL_PROJECTION); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + core::matrix4 m; + m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-renderTargetSize.Height), -1.0, 1.0); + m.setTranslation(core::vector3df(-1,1,0)); + glLoadMatrixf(m.pointer()); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.375, 0.375, 0.0); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + Transformation3DChanged = false; + } + + if (alphaChannel || alpha) + { + glEnable(GL_BLEND); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.f); + } + else + { + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + } + + if (texture) + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + if (alphaChannel) + { + // if alpha and alpha texture just modulate, otherwise use only the alpha channel + if (alpha) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + else + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); + // rgb always modulates + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); + } + } + else + { + if (alpha) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); + // rgb always modulates + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); + } + else + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + } + + CurrentRenderMode = ERM_2D; +} + + +//! \return Returns the name of the video driver. +const wchar_t* COpenGLDriver::getName() const +{ + return Name.c_str(); +} + + +//! deletes all dynamic lights there are +void COpenGLDriver::deleteAllDynamicLights() +{ + for (s32 i=0; i& area) +{ + core::rect vp = area; + core::rect rendert(0,0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height); + vp.clipAgainst(rendert); + + if (vp.getHeight()>0 && vp.getWidth()>0) + glViewport(vp.UpperLeftCorner.X, + getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), + vp.getWidth(), vp.getHeight()); + + ViewPort = vp; +} + + +//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do +//! this: First, draw all geometry. Then use this method, to draw the shadow +//! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow. +void COpenGLDriver::drawStencilShadowVolume(const core::vector3df* triangles, s32 count, bool zfail) +{ + if (!StencilBuffer || !count) + return; + + // unset last 3d material + if (CurrentRenderMode == ERM_3D && + static_cast(Material.MaterialType) < MaterialRenderers.size()) + { + MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial(); + ResetRenderStates = true; + } + + // store current OpenGL state + glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | + GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT); + + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glDepthFunc(GL_LEQUAL); + glDepthMask(GL_FALSE); // no depth buffer writing + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); // no color buffer drawing + glEnable(GL_STENCIL_TEST); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(0.0f, 1.0f); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3,GL_FLOAT,sizeof(core::vector3df),&triangles[0]); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + // The first parts are not correctly working, yet. +#if 0 +#ifdef GL_EXT_stencil_two_side + if (FeatureAvailable[IRR_EXT_stencil_two_side]) + { + glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT); +#ifdef GL_NV_depth_clamp + if (FeatureAvailable[IRR_NV_depth_clamp]) + glEnable(GL_DEPTH_CLAMP_NV); +#endif + glDisable(GL_CULL_FACE); + if (!zfail) + { + // ZPASS Method + + extGlActiveStencilFace(GL_BACK); + if (FeatureAvailable[IRR_EXT_stencil_wrap]) + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP_EXT); + else + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + extGlActiveStencilFace(GL_FRONT); + if (FeatureAvailable[IRR_EXT_stencil_wrap]) + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP_EXT); + else + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + glDrawArrays(GL_TRIANGLES,0,count); + } + else + { + // ZFAIL Method + + extGlActiveStencilFace(GL_BACK); + if (FeatureAvailable[IRR_EXT_stencil_wrap]) + glStencilOp(GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP); + else + glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + extGlActiveStencilFace(GL_FRONT); + if (FeatureAvailable[IRR_EXT_stencil_wrap]) + glStencilOp(GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP); + else + glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + glDrawArrays(GL_TRIANGLES,0,count); + } + } + else +#endif + if (FeatureAvailable[IRR_ATI_separate_stencil]) + { + glDisable(GL_CULL_FACE); + if (!zfail) + { + // ZPASS Method + + extGlStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR); + extGlStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR); + extGlStencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, 0, ~0); + glStencilMask(~0); + + glDrawArrays(GL_TRIANGLES,0,count); + } + else + { + // ZFAIL Method + + extGlStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP); + extGlStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP); + extGlStencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, 0, ~0); + + glDrawArrays(GL_TRIANGLES,0,count); + } + } + else +#endif + { + glEnable(GL_CULL_FACE); + if (!zfail) + { + // ZPASS Method + + glCullFace(GL_BACK); + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + glDrawArrays(GL_TRIANGLES,0,count); + + glCullFace(GL_FRONT); + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); + glDrawArrays(GL_TRIANGLES,0,count); + } + else + { + // ZFAIL Method + + glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); + glCullFace(GL_FRONT); + glDrawArrays(GL_TRIANGLES,0,count); + + glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); + glCullFace(GL_BACK); + glDrawArrays(GL_TRIANGLES,0,count); + } + } + + glDisableClientState(GL_VERTEX_ARRAY); //not stored on stack + glPopAttrib(); +} + + + +void COpenGLDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, + video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) +{ + if (!StencilBuffer) + return; + + disableTextures(); + + // store attributes + glPushAttrib( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT ); + + glDisable( GL_LIGHTING ); + glDisable(GL_FOG); + glDepthMask(GL_FALSE); + + glShadeModel( GL_FLAT ); + glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable( GL_STENCIL_TEST ); + glStencilFunc(GL_NOTEQUAL, 0, ~0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + // draw a shadow rectangle covering the entire screen using stencil buffer + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glBegin(GL_QUADS); + + glColor4ub (leftDownEdge.getRed(), leftDownEdge.getGreen(), leftDownEdge.getBlue(), leftDownEdge.getAlpha() ); + glVertex3f(-1.1f,-1.1f,0.9f); + + glColor4ub (leftUpEdge.getRed(), leftUpEdge.getGreen(), leftUpEdge.getBlue(), leftUpEdge.getAlpha() ); + glVertex3f(-1.1f, 1.1f,0.9f); + + glColor4ub (rightUpEdge.getRed(), rightUpEdge.getGreen(), rightUpEdge.getBlue(), rightUpEdge.getAlpha() ); + glVertex3f( 1.1f, 1.1f,0.9f); + + glColor4ub (rightDownEdge.getRed(), rightDownEdge.getGreen(), rightDownEdge.getBlue(), rightDownEdge.getAlpha() ); + glVertex3f( 1.1f,-1.1f,0.9f); + + glEnd(); + + if (clearStencilBuffer) + glClear(GL_STENCIL_BUFFER_BIT); + + // restore settings + glPopMatrix(); + glPopAttrib(); +} + + +//! Sets the fog mode. +void COpenGLDriver::setFog(SColor c, bool linearFog, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) +{ + CNullDriver::setFog(c, linearFog, start, end, density, pixelFog, rangeFog); + + glFogf(GL_FOG_MODE, GLfloat(linearFog ? GL_LINEAR : GL_EXP)); +#ifdef GL_EXT_fog_coord + if (FeatureAvailable[IRR_EXT_fog_coord]) + glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH); +#endif + + if(linearFog) + { + glFogf(GL_FOG_START, start); + glFogf(GL_FOG_END, end); + } + else + glFogf(GL_FOG_DENSITY, density); + + if (pixelFog) + glHint(GL_FOG_HINT, GL_NICEST); + else + glHint(GL_FOG_HINT, GL_FASTEST); + + SColorf color(c); + GLfloat data[4] = {color.r, color.g, color.b, color.a}; + glFogfv(GL_FOG_COLOR, data); +} + + + +//! Draws a 3d line. +void COpenGLDriver::draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color) +{ + setRenderStates3DMode(); + + glBegin(GL_LINES); + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glVertex3f(start.X, start.Y, start.Z); + + glVertex3f(end.X, end.Y, end.Z); + glEnd(); +} + + + +//! Only used by the internal engine. Used to notify the driver that +//! the window was resized. +void COpenGLDriver::OnResize(const core::dimension2d& size) +{ + CNullDriver::OnResize(size); + glViewport(0, 0, size.Width, size.Height); + Transformation3DChanged = true; +} + + +//! Returns type of video driver +E_DRIVER_TYPE COpenGLDriver::getDriverType() const +{ + return EDT_OPENGL; +} + + +//! returns color format +ECOLOR_FORMAT COpenGLDriver::getColorFormat() const +{ + return ColorFormat; +} + + +//! Sets a vertex shader constant. +void COpenGLDriver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) +{ +#ifdef GL_ARB_vertex_program + for (s32 i=0; isetPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); + return false; +} + + +//! Adds a new material renderer to the VideoDriver, using pixel and/or +//! vertex shaders to render geometry. +s32 COpenGLDriver::addShaderMaterial(const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData) +{ + s32 nr = -1; + COpenGLShaderMaterialRenderer* r = new COpenGLShaderMaterialRenderer( + this, nr, vertexShaderProgram, pixelShaderProgram, + callback, getMaterialRenderer(baseMaterial), userData); + + r->drop(); + return nr; +} + + +//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry. +s32 COpenGLDriver::addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) +{ + s32 nr = -1; + + COpenGLSLMaterialRenderer* r = new COpenGLSLMaterialRenderer( + this, nr, vertexShaderProgram, vertexShaderEntryPointName, + vsCompileTarget, pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget, + callback,getMaterialRenderer(baseMaterial), userData); + + r->drop(); + return nr; +} + +//! Returns a pointer to the IVideoDriver interface. (Implementation for +//! IMaterialRendererServices) +IVideoDriver* COpenGLDriver::getVideoDriver() +{ + return this; +} + + +//! Returns pointer to the IGPUProgrammingServices interface. +IGPUProgrammingServices* COpenGLDriver::getGPUProgrammingServices() +{ + return this; +} + + +ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d& size, const c8* name) +{ + //disable mip-mapping + bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); + + video::ITexture* rtt = 0; + if (name==0) + name="rt"; +#if defined(GL_EXT_framebuffer_object) + // if driver supports FrameBufferObjects, use them + if (queryFeature(EVDF_FRAMEBUFFER_OBJECT)) + { + rtt = new COpenGLFBOTexture(size, name, this); + if (rtt) + { + addTexture(rtt); + ITexture* tex = createDepthTexture(rtt); + if (tex) + { + static_cast(tex)->attach(rtt); + tex->drop(); + } + rtt->drop(); + } + } + else +#endif + { + // the simple texture is only possible for size <= screensize + // we try to find an optimal size with the original constraints + core::dimension2di destSize(core::min_(size.Width,ScreenSize.Width), core::min_(size.Height,ScreenSize.Height)); + destSize = destSize.getOptimalSize((size==size.getOptimalSize()), false, false); + rtt = addTexture(destSize, name, ECF_A8R8G8B8); + if (rtt) + { + static_cast(rtt)->setIsRenderTarget(true); + } + } + + //restore mip-mapping + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels); + + return rtt; +} + + +//! Returns the maximum amount of primitives (mostly vertices) which +//! the device is able to render with one drawIndexedTriangleList +//! call. +u32 COpenGLDriver::getMaximalPrimitiveCount() const +{ + return 0x7fffffff; +} + + +//! set or reset render target +bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, + bool clearZBuffer, SColor color) +{ + // check for right driver type + + if (texture && texture->getDriverType() != EDT_OPENGL) + { + os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); + return false; + } + + // check if we should set the previous RT back + + setTexture(0, 0); + ResetRenderStates=true; + if (RenderTargetTexture!=0) + { + RenderTargetTexture->unbindRTT(); + } + + if (texture) + { + // we want to set a new target. so do this. + glViewport(0, 0, texture->getSize().Width, texture->getSize().Height); + RenderTargetTexture = static_cast(texture); + RenderTargetTexture->bindRTT(); + CurrentRendertargetSize = texture->getSize(); + } + else + { + glViewport(0,0,ScreenSize.Width,ScreenSize.Height); + RenderTargetTexture = 0; + CurrentRendertargetSize = core::dimension2d(0,0); + } + + GLbitfield mask = 0; + if (clearBackBuffer) + { + const f32 inv = 1.0f / 255.0f; + glClearColor(color.getRed() * inv, color.getGreen() * inv, + color.getBlue() * inv, color.getAlpha() * inv); + + mask |= GL_COLOR_BUFFER_BIT; + } + if (clearZBuffer) + { + glDepthMask(GL_TRUE); + LastMaterial.ZWriteEnable=true; + mask |= GL_DEPTH_BUFFER_BIT; + } + + glClear(mask); + + return true; +} + + +// returns the current size of the screen or rendertarget +const core::dimension2d& COpenGLDriver::getCurrentRenderTargetSize() const +{ + if ( CurrentRendertargetSize.Width == 0 ) + return ScreenSize; + else + return CurrentRendertargetSize; +} + + +//! Clears the ZBuffer. +void COpenGLDriver::clearZBuffer() +{ + GLboolean enabled = GL_TRUE; + glGetBooleanv(GL_DEPTH_WRITEMASK, &enabled); + + glDepthMask(GL_TRUE); + glClear(GL_DEPTH_BUFFER_BIT); + + glDepthMask(enabled); +} + + +//! Returns an image created from the last rendered frame. +IImage* COpenGLDriver::createScreenShot() +{ + IImage* newImage = new CImage(ECF_R8G8B8, ScreenSize); + + u8* pixels = static_cast(newImage->lock()); + if (!pixels) + { + newImage->drop(); + return 0; + } + + // allows to read pixels in top-to-bottom order +#ifdef GL_MESA_pack_invert + if (FeatureAvailable[IRR_MESA_pack_invert]) + glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); +#endif + + // We want to read the front buffer to get the latest render finished. + glReadBuffer(GL_FRONT); + glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, GL_RGB, GL_UNSIGNED_BYTE, pixels); + glReadBuffer(GL_BACK); + +#ifdef GL_MESA_pack_invert + if (FeatureAvailable[IRR_MESA_pack_invert]) + glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE); + else +#endif + { + // opengl images are horizontally flipped, so we have to fix that here. + const s32 pitch=newImage->getPitch(); + u8* p2 = pixels + (ScreenSize.Height - 1) * pitch; + u8* tmpBuffer = new u8[pitch]; + for (s32 i=0; i < ScreenSize.Height; i += 2) + { + memcpy(tmpBuffer, pixels, pitch); + memcpy(pixels, p2, pitch); + memcpy(p2, tmpBuffer, pitch); + pixels += pitch; + p2 -= pitch; + } + delete [] tmpBuffer; + } + + newImage->unlock(); + + if (testGLError()) + { + newImage->drop(); + return 0; + } + + return newImage; +} + + +//! get depth texture for the given render target texture +ITexture* COpenGLDriver::createDepthTexture(ITexture* texture, bool shared) +{ + if ((texture->getDriverType() != EDT_OPENGL) || (!texture->isRenderTarget())) + return 0; + COpenGLTexture* tex = static_cast(texture); + + if (!tex->isFrameBufferObject()) + return 0; + + if (shared) + { + for (u32 i=0; igetSize()==texture->getSize()) + { + DepthTextures[i]->grab(); + return DepthTextures[i]; + } + } + DepthTextures.push_back(new COpenGLFBODepthTexture(texture->getSize(), "depth1", this)); + return DepthTextures.getLast(); + } + return (new COpenGLFBODepthTexture(texture->getSize(), "depth1", this)); +} + + +void COpenGLDriver::removeDepthTexture(ITexture* texture) +{ + for (u32 i=0; i= MaxUserClipPlanes) + return false; + + UserClipPlane[index]=plane; + enableClipPlane(index, enable); + return true; +} + + +void COpenGLDriver::uploadClipPlane(u32 index) +{ + // opengl needs an array of doubles for the plane equation + double clip_plane[4]; + clip_plane[0] = UserClipPlane[index].Normal.X; + clip_plane[1] = UserClipPlane[index].Normal.Y; + clip_plane[2] = UserClipPlane[index].Normal.Z; + clip_plane[3] = UserClipPlane[index].D; + glClipPlane(GL_CLIP_PLANE0 + index, clip_plane); +} + + +//! Enable/disable a clipping plane. +void COpenGLDriver::enableClipPlane(u32 index, bool enable) +{ + if (index >= MaxUserClipPlanes) + return; + if (enable) + { + if (!UserClipPlaneEnabled[index]) + { + uploadClipPlane(index); + glEnable(GL_CLIP_PLANE0 + index); + } + } + else + glDisable(GL_CLIP_PLANE0 + index); + + UserClipPlaneEnabled[index]=enable; +} + + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_OPENGL_ + +namespace irr +{ +namespace video +{ + + +// ----------------------------------- +// WINDOWS VERSION +// ----------------------------------- +#ifdef _IRR_USE_WINDOWS_DEVICE_ +IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params, + io::IFileSystem* io) +{ +#ifdef _IRR_COMPILE_WITH_OPENGL_ + COpenGLDriver* ogl = new COpenGLDriver(params, io); + if (!ogl->initDriver(params)) + { + ogl->drop(); + ogl = 0; + } + return ogl; +#else + return 0; +#endif // _IRR_COMPILE_WITH_OPENGL_ +} +#endif // _IRR_USE_WINDOWS_DEVICE_ + +// ----------------------------------- +// MACOSX VERSION +// ----------------------------------- +#if defined(_IRR_USE_OSX_DEVICE_) +IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceMacOSX *device) +{ +#ifdef _IRR_COMPILE_WITH_OPENGL_ + return new COpenGLDriver(params, io, device); +#else + return 0; +#endif // _IRR_COMPILE_WITH_OPENGL_ +} +#endif // _IRR_USE_OSX_DEVICE_ + +// ----------------------------------- +// X11/SDL VERSION +// ----------------------------------- +#if defined(_IRR_USE_LINUX_DEVICE_) || defined(_IRR_USE_SDL_DEVICE_) +IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io) +{ +#ifdef _IRR_COMPILE_WITH_OPENGL_ + return new COpenGLDriver(params, io); +#else + return 0; +#endif // _IRR_COMPILE_WITH_OPENGL_ +} +#endif // _IRR_USE_LINUX_DEVICE_ + +} // end namespace +} // end namespace + + diff --git a/irrlicht_1.5_update/source/Irrlicht/COpenGLDriver.h b/irrlicht_1.5_update/source/Irrlicht/COpenGLDriver.h new file mode 100755 index 000000000..0a5a5a77f --- /dev/null +++ b/irrlicht_1.5_update/source/Irrlicht/COpenGLDriver.h @@ -0,0 +1,432 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_VIDEO_OPEN_GL_H_INCLUDED__ +#define __C_VIDEO_OPEN_GL_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#if defined(_IRR_WINDOWS_API_) + // include windows headers for HWND + #define WIN32_LEAN_AND_MEAN + #include +#elif defined(_IRR_USE_OSX_DEVICE_) + #include "CIrrDeviceMacOSX.h" +#endif + +#include "SIrrCreationParameters.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "CNullDriver.h" +#include "IMaterialRendererServices.h" +#include "COpenGLExtensionHandler.h" + +#if defined(_IRR_WINDOWS_API_) + #include + #include "glext.h" + #include "wglext.h" +#ifdef _MSC_VER + #pragma comment(lib, "OpenGL32.lib") + #pragma comment(lib, "GLu32.lib") +#endif +#elif defined(_IRR_USE_OSX_DEVICE_) + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #define GL_GLEXT_LEGACY 1 + #endif + #include + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #include "glext.h" + #endif +#elif defined(_IRR_USE_SDL_DEVICE_) + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #define GL_GLEXT_LEGACY 1 + #define GLX_GLXEXT_LEGACY 1 + #else + #define GL_GLEXT_PROTOTYPES 1 + #define GLX_GLXEXT_PROTOTYPES 1 + #endif + #define NO_SDL_GLEXT + #include + #include "glext.h" +#else + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #define GL_GLEXT_LEGACY 1 + #define GLX_GLXEXT_LEGACY 1 + #else + #define GL_GLEXT_PROTOTYPES 1 + #define GLX_GLXEXT_PROTOTYPES 1 + #endif + #include + #include + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #include "glext.h" + #undef GLX_ARB_get_proc_address // avoid problems with local glxext.h + #include "glxext.h" + #endif +#endif + +namespace irr +{ +namespace video +{ + class COpenGLTexture; + + class COpenGLDriver : public CNullDriver, public IMaterialRendererServices, public COpenGLExtensionHandler + { + public: + + #if defined(_IRR_WINDOWS_API_) || defined(_IRR_USE_LINUX_DEVICE_) || defined(_IRR_USE_SDL_DEVICE_) + COpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io); + #endif + + #ifdef _IRR_USE_OSX_DEVICE_ + COpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceMacOSX *device); + #endif + + #ifdef _IRR_WINDOWS_API_ + //! inits the windows specific parts of the open gl driver + bool initDriver(SIrrlichtCreationParameters params); + #endif + + //! destructor + virtual ~COpenGLDriver(); + + //! clears the zbuffer + virtual bool beginScene(bool backBuffer=true, bool zBuffer=true, + SColor color=SColor(255,0,0,0), + void* windowId=0, + core::rect* sourceRect=0); + + //! presents the rendered scene on the screen, returns false if failed + virtual bool endScene(); + + //! sets transformation + virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat); + + + struct SHWBufferLink_opengl : public SHWBufferLink + { + SHWBufferLink_opengl(const scene::IMeshBuffer *_MeshBuffer): SHWBufferLink(_MeshBuffer), vbo_verticesID(0),vbo_indicesID(0){} + + GLuint vbo_verticesID; //tmp + GLuint vbo_indicesID; //tmp + + GLuint vbo_verticesSize; //tmp + GLuint vbo_indicesSize; //tmp + + }; + + bool updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer); + bool updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer); + + //! updates hardware buffer if needed + virtual bool updateHardwareBuffer(SHWBufferLink *HWBuffer); + + //! Create hardware buffer from mesh + virtual SHWBufferLink *createHardwareBuffer(const scene::IMeshBuffer* mb); + + //! Delete hardware buffer (only some drivers can) + virtual void deleteHardwareBuffer(SHWBufferLink *HWBuffer); + + //! Draw hardware buffer + virtual void drawHardwareBuffer(SHWBufferLink *HWBuffer); + + //! draws a vertex primitive list + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType); + + //! queries the features of the driver, returns true if feature is available + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const + { + return FeatureEnabled[feature] && COpenGLExtensionHandler::queryFeature(feature); + } + + //! Sets a material. All 3d drawing functions draw geometry now + //! using this material. + //! \param material: Material to be used from now on. + virtual void setMaterial(const SMaterial& material); + + //! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted. + virtual void draw2DImage(const video::ITexture* texture, const core::position2d& destPos, + const core::rect& sourceRect, const core::rect* clipRect = 0, + SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false); + + //! draws a set of 2d images, using a color and the alpha + /** channel of the texture if desired. The images are drawn + beginning at pos and concatenated in one line. All drawings + are clipped against clipRect (if != 0). + The subtextures are defined by the array of sourceRects + and are chosen by the indices given. + \param texture: Texture to be drawn. + \param pos: Upper left 2d destination position where the image will be drawn. + \param sourceRects: Source rectangles of the image. + \param indices: List of indices which choose the actual rectangle used each time. + \param clipRect: Pointer to rectangle on the screen where the image is clipped to. + This pointer can be 0. Then the image is not clipped. + \param color: Color with which the image is colored. + Note that the alpha component is used: If alpha is other than 255, the image will be transparent. + \param useAlphaChannelOfTexture: If true, the alpha channel of the texture is + used to draw the image. */ + virtual void draw2DImage(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + const core::rect* clipRect=0, + SColor color=SColor(255,255,255,255), + bool useAlphaChannelOfTexture=false); + + //! Draws a part of the texture into the rectangle. + virtual void draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect = 0, + const video::SColor* const colors=0, bool useAlphaChannelOfTexture=false); + + //! draw an 2d rectangle + virtual void draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip = 0); + + //!Draws an 2d rectangle with a gradient. + virtual void draw2DRectangle(const core::rect& pos, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip = 0); + + //!Draws a 2d polygon with optional colors per vertex and a texture. + virtual void draw2DPolygon(const core::array &vertices, + const core::array *colors=NULL, + const video::ITexture *texture=NULL, + bool useAlphaChannelOfTexture=false, + const core::array *coordinates=NULL); + + + //! Draws a 2d line. + virtual void draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color=SColor(255,255,255,255)); + + //! Draws a single pixel + virtual void drawPixel(u32 x, u32 y, const SColor & color); + + //! Draws a 3d line. + virtual void draw3DLine(const core::vector3df& start, + const core::vector3df& end, + SColor color = SColor(255,255,255,255)); + + //! \return Returns the name of the video driver. Example: In case of the Direct3D8 + //! driver, it would return "Direct3D8.1". + virtual const wchar_t* getName() const; + + //! deletes all dynamic lights there are + virtual void deleteAllDynamicLights(); + + //! adds a dynamic light + virtual void addDynamicLight(const SLight& light); + + //! returns the maximal amount of dynamic lights the device can handle + virtual u32 getMaximalDynamicLightAmount() const; + + //! Sets the dynamic ambient light color. The default color is + //! (0,0,0,0) which means it is dark. + //! \param color: New color of the ambient light. + virtual void setAmbientLight(const SColorf& color); + + //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do + //! this: First, draw all geometry. Then use this method, to draw the shadow + //! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow. + virtual void drawStencilShadowVolume(const core::vector3df* triangles, s32 count, bool zfail); + + //! Fills the stencil shadow with color. After the shadow volume has been drawn + //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this + //! to draw the color of the shadow. + virtual void drawStencilShadow(bool clearStencilBuffer=false, + video::SColor leftUpEdge = video::SColor(0,0,0,0), + video::SColor rightUpEdge = video::SColor(0,0,0,0), + video::SColor leftDownEdge = video::SColor(0,0,0,0), + video::SColor rightDownEdge = video::SColor(0,0,0,0)); + + //! sets a viewport + virtual void setViewPort(const core::rect& area); + + //! Sets the fog mode. + virtual void setFog(SColor color, bool linearFog, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog); + + //! Only used by the internal engine. Used to notify the driver that + //! the window was resized. + virtual void OnResize(const core::dimension2d& size); + + //! Returns type of video driver + virtual E_DRIVER_TYPE getDriverType() const; + + //! get color format of the current color buffer + virtual ECOLOR_FORMAT getColorFormat() const; + + //! Returns the transformation set by setTransform + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const; + + //! Can be called by an IMaterialRenderer to make its work easier. + virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderstates); + + //! Sets a vertex shader constant. + virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1); + + //! Sets a pixel shader constant. + virtual void setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1); + + //! Sets a constant for the vertex shader based on a name. + virtual bool setVertexShaderConstant(const c8* name, const f32* floats, int count); + + //! Sets a constant for the pixel shader based on a name. + virtual bool setPixelShaderConstant(const c8* name, const f32* floats, int count); + + //! sets the current Texture + //! Returns whether setting was a success or not. + bool setTexture(u32 stage, const video::ITexture* texture); + + //! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled. + //! Returns whether disabling was successful or not. + bool disableTextures(u32 fromStage=0); + + //! Adds a new material renderer to the VideoDriver, using + //! extGLGetObjectParameteriv(shaderHandle, GL_OBJECT_COMPILE_STATUS_ARB, &status) + //! pixel and/or vertex shaders to render geometry. + virtual s32 addShaderMaterial(const c8* vertexShaderProgram, const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, s32 userData); + + //! Adds a new material renderer to the VideoDriver, using GLSL to render geometry. + virtual s32 addHighLevelShaderMaterial(const c8* vertexShaderProgram, const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, const c8* pixelShaderProgram, const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, + s32 userData); + + //! Returns pointer to the IGPUProgrammingServices interface. + virtual IGPUProgrammingServices* getGPUProgrammingServices(); + + //! Returns a pointer to the IVideoDriver interface. (Implementation for + //! IMaterialRendererServices) + virtual IVideoDriver* getVideoDriver(); + + //! Returns the maximum amount of primitives (mostly vertices) which + //! the device is able to render with one drawIndexedTriangleList + //! call. + virtual u32 getMaximalPrimitiveCount() const; + + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const c8* name); + + virtual bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer, + bool clearZBuffer, SColor color); + + //! Clears the ZBuffer. + virtual void clearZBuffer(); + + //! Returns an image created from the last rendered frame. + virtual IImage* createScreenShot(); + + //! checks if an OpenGL error has happend and prints it + //! for performance reasons only available in debug mode + bool testGLError(); + + //! Set/unset a clipping plane. + //! There are at least 6 clipping planes available for the user to set at will. + //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes. + //! \param plane: The plane itself. + //! \param enable: If true, enable the clipping plane else disable it. + virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable=false); + + //! Enable/disable a clipping plane. + //! There are at least 6 clipping planes available for the user to set at will. + //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes. + //! \param enable: If true, enable the clipping plane else disable it. + virtual void enableClipPlane(u32 index, bool enable); + + //! Returns the graphics card vendor name. + virtual core::stringc getVendorInfo() {return vendorName;} + + ITexture* createDepthTexture(ITexture* texture, bool shared=true); + void removeDepthTexture(ITexture* texture); + + private: + + void uploadClipPlane(u32 index); + + //! inits the parts of the open gl driver used on all platforms + bool genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer); + //! returns a device dependent texture from a software surface (IImage) + virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const char* name); + + //! creates a transposed matrix in supplied GLfloat array to pass to OpenGL + inline void createGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m); + inline void createGLTextureMatrix(GLfloat gl_matrix[16], const core::matrix4& m); + + //! Set GL pipeline to desired texture wrap modes of the material + void setWrapMode(const SMaterial& material); + + //! sets the needed renderstates + void setRenderStates3DMode(); + + //! sets the needed renderstates + void setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel); + + // returns the current size of the screen or rendertarget + virtual const core::dimension2d& getCurrentRenderTargetSize() const; + + void createMaterialRenderers(); + + + core::stringw Name; + core::matrix4 Matrices[ETS_COUNT]; + core::array ColorBuffer; + + //! enumeration for rendering modes such as 2d and 3d for minizing the switching of renderStates. + enum E_RENDER_MODE + { + ERM_NONE = 0, // no render state has been set yet. + ERM_2D, // 2d drawing rendermode + ERM_3D // 3d rendering mode + }; + + E_RENDER_MODE CurrentRenderMode; + //! bool to make all renderstates reset if set to true. + bool ResetRenderStates; + bool Transformation3DChanged; + bool AntiAlias; + + SMaterial Material, LastMaterial; + COpenGLTexture* RenderTargetTexture; + const ITexture* CurrentTexture[MATERIAL_MAX_TEXTURES]; + core::array DepthTextures; + s32 LastSetLight; + core::array UserClipPlane; + core::array UserClipPlaneEnabled; + + core::dimension2d CurrentRendertargetSize; + + core::stringc vendorName; + + core::matrix4 TextureFlipMatrix; + + //! Color buffer format + ECOLOR_FORMAT ColorFormat; + + #ifdef _IRR_WINDOWS_API_ + HDC HDc; // Private GDI Device Context + HWND Window; + HGLRC HRc; // Permanent Rendering Context + #elif defined(_IRR_USE_LINUX_DEVICE_) + GLXDrawable Drawable; + #elif defined(_IRR_USE_OSX_DEVICE_) + CIrrDeviceMacOSX *_device; + #endif + }; + +} // end namespace video +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_OPENGL_ +#endif + diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 40848a917..75d081623 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -440,6 +440,14 @@ void IrrDriver::removeMesh(scene::IMesh *mesh) { m_scene_manager->getMeshCache()->removeMesh(mesh); } // removeMesh +// ---------------------------------------------------------------------------- +/** Removes a texture from irrlicht's texture cache. + * \param t The texture to remove. + */ +void IrrDriver::removeTexture(video::ITexture *t) +{ + m_video_driver->removeTexture(t); +} // removeTexture // ---------------------------------------------------------------------------- /** Adds an animated mesh to the scene. @@ -450,6 +458,7 @@ scene::IAnimatedMeshSceneNode *IrrDriver::addAnimatedMesh(scene::IAnimatedMesh * return m_scene_manager->addAnimatedMeshSceneNode(mesh); } // addAnimatedMesh + // ---------------------------------------------------------------------------- /** Adds a sky dome. Documentation from irrlicht: * A skydome is a large (half-) sphere with a panoramic texture on the inside diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index ec043bc0b..81b5c0d96 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -94,6 +94,7 @@ public: scene::ISceneNode *addSkyBox(const std::vector &texture_names); void removeNode(scene::ISceneNode *node); void removeMesh(scene::IMesh *mesh); + void removeTexture(video::ITexture *t); scene::IAnimatedMeshSceneNode *addAnimatedMesh(scene::IAnimatedMesh *mesh); scene::ICameraSceneNode @@ -110,6 +111,12 @@ public: void beginRenderToTexture(const core::dimension2di &dimension, const std::string &name); video::ITexture *endRenderToTexture(); + void draw2dTriangle(const core::vector2df &a, const core::vector2df &b, + const core::vector2df &c, + const video::ITexture *texture = NULL, + const video::SColor *ca=NULL, const video::SColor *cb=NULL, + const video::SColor *cc=NULL); + }; // IrrDriver extern IrrDriver *irr_driver; diff --git a/src/io/xml_node.cpp b/src/io/xml_node.cpp index 00e00010c..9aa66fff1 100644 --- a/src/io/xml_node.cpp +++ b/src/io/xml_node.cpp @@ -202,6 +202,28 @@ int XMLNode::get(const std::string &attribute, Vec3 *value) const return 1; } // get(Vec3) +// ---------------------------------------------------------------------------- +int XMLNode::get(const std::string &attribute, video::SColor *color) const +{ + std::string s; + if(!get(attribute, &s)) return 0; + + std::vector v = StringUtils::split(s,' '); + if(v.size()<3 || v.size()>4) return 0; + if(v.size()==3) + { + color->setRed (atoi(v[0].c_str())); + color->setGreen(atoi(v[1].c_str())); + color->setBlue (atoi(v[2].c_str())); + } + else + color->set(atoi(v[0].c_str()), + atoi(v[1].c_str()), + atoi(v[2].c_str()), + atoi(v[3].c_str())); + return 1; +} // get(SColor) + // ---------------------------------------------------------------------------- int XMLNode::get(const std::string &attribute, video::SColorf *color) const { diff --git a/src/io/xml_node.hpp b/src/io/xml_node.hpp index 5d6f8b84b..42956ffaa 100644 --- a/src/io/xml_node.hpp +++ b/src/io/xml_node.hpp @@ -56,6 +56,7 @@ public: int get(const std::string &attribute, core::vector2df *value) const; int get(const std::string &attribute, core::vector3df *value) const; int get(const std::string &attribute, video::SColorf *value) const; + int get(const std::string &attribute, video::SColor *value) const; int get(const std::string &attribute, std::vector *value) const; int get(const std::string &attribute, std::vector *value) const; int get(const std::string &attribute, std::vector *value) const; diff --git a/src/karts/kart.hpp b/src/karts/kart.hpp index e02a5f859..5a420a81b 100644 --- a/src/karts/kart.hpp +++ b/src/karts/kart.hpp @@ -196,7 +196,7 @@ public: // Functions to access the current kart properties (which might get changed, // e.g. mass increase or air_friction increase depending on attachment etc.) // ------------------------------------------------------------------------- - const Vec3 &getColor () const {return m_kart_properties->getColor();} + const video::SColor &getColor () const {return m_kart_properties->getColor();} float getMass () const { return m_kart_properties->getMass() diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 2cd69385e..677c0795e 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -69,8 +69,9 @@ KartProperties::KartProperties() : m_icon_material(0) m_gravity_center_shift = Vec3(UNDEFINED); m_has_skidmarks = true; m_version = 0; - m_color.setValue(1.0f, 0.0f, 0.0f); - m_engine_sfx_type = SFXManager::SOUND_ENGINE_SMALL; + m_color = video::SColor(255, 0, 0, 0); + m_shape = 32; // close enough to a circle. + m_engine_sfx_type = SFXManager::SOUND_ENGINE_SMALL; } // KartProperties //----------------------------------------------------------------------------- @@ -183,8 +184,9 @@ void KartProperties::getAllData(const lisp::Lisp* lisp) lisp->get("name", m_name); lisp->get("icon-file", m_icon_file); lisp->get("shadow-file", m_shadow_file); - lisp->get("rgb", m_color); - + Vec3 c; + lisp->get("rgb", c); + m_color.set(255, (int)(255*c.getX()), (int)(255*c.getY()), (int)(255*c.getZ())); lisp->get("engine-power", m_engine_power, 3); lisp->get("time-full-steer", m_time_full_steer); lisp->get("time-full-steer-ai", m_time_full_steer_ai); diff --git a/src/karts/kart_properties.hpp b/src/karts/kart_properties.hpp index 5920d1d35..6a60d9267 100644 --- a/src/karts/kart_properties.hpp +++ b/src/karts/kart_properties.hpp @@ -23,6 +23,9 @@ #include #include +#include "irrlicht.h" +using namespace irr; + #include "audio/sfx_manager.hpp" #include "karts/kart_model.hpp" #include "lisp/lisp.hpp" @@ -30,7 +33,6 @@ #include "utils/vec3.hpp" class Material; -class ssgEntity; /** This class stores the properties of a kart. This includes size, name, * identifier, physical properties etc. It is atm also the base class for @@ -62,9 +64,10 @@ private: * character select screen. */ std::string m_shadow_file; /**< Filename of the image file that * contains the shadow for this kart.*/ - Vec3 m_color; /**< Color the represents the kart in the + video::SColor m_color; /**< Color the represents the kart in the * status bar and on the track-view. */ - + int m_shape; /**< Number of vertices in polygon when + * drawing the dot on the mini map. */ // Physic properties // ----------------- float m_mass; /**< Weight of kart. */ @@ -88,14 +91,9 @@ private: kart length. */ m_max_radius; /**< Largest turn radius. */ - //ssgEntity *m_wheel_model[4]; /**< The four wheel models. */ std::string m_wheel_filename[4]; /**< Filename of the wheel models. */ /** Radius of the graphical wheels. */ float m_wheel_graphics_radius[4]; - //ssgTransform - // *m_wheel_transform[4]; /**< The transform for the wheels, used - // * to rotate the wheels and display - // * the suspension in the race. */ float m_rubber_band_max_length;/**< Max. length of plunger rubber band.*/ float m_rubber_band_force; /**< Force of an attached rubber band.*/ float m_rubber_band_duration;/**< Duration a rubber band works. */ @@ -173,7 +171,11 @@ public: const std::string& getIconFile () const {return m_icon_file; } /** Returns the version of the .kart file. */ int getVersion () const {return m_version; } - const Vec3 &getColor () const {return m_color; } + /** Returns the dot color to use for this kart in the race gui. */ + const video::SColor &getColor () const {return m_color; } + /** Returns the number of edges for the polygon used to draw the dot of + * this kart on the mini map of the race gui. */ + int getShape () const {return m_shape; } const std::vector& getGroups () const {return m_groups; } float getMass () const {return m_mass; } diff --git a/src/karts/kart_properties_manager.hpp b/src/karts/kart_properties_manager.hpp index 207e640f7..262ea1c02 100644 --- a/src/karts/kart_properties_manager.hpp +++ b/src/karts/kart_properties_manager.hpp @@ -17,8 +17,8 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#ifndef HEADER_KARTPROPERTIESMANAGER_HPP -#define HEADER_KARTPROPERTIESMANAGER_HPP +#ifndef HEADER_KART_PROPERTIES_MANAGER_HPP +#define HEADER_KART_PROPERTIES_MANAGER_HPP #include #include diff --git a/src/main.cpp b/src/main.cpp index cadf290ce..3b14347e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -253,6 +253,7 @@ int handleCmdLine(int argc, char **argv) std::string filename=file_manager->getKartFile(std::string(argv[i+1])+".tkkf"); if(filename!="") { + race_manager->setNumLocalPlayers(1); race_manager->setLocalKartInfo(0, argv[i+1]); fprintf ( stdout, "You choose to use kart '%s'.\n", argv[i+1] ) ; } diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 0052ed1f6..684941ac2 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -73,7 +73,11 @@ void World::init() TimedRace::setClockMode( CHRONO ); m_use_highscores = true; - + + // Create the race gui before anything else is attached to the scene node. + // This allows the race gui to do any rendering on texture. + m_race_gui = new RaceGUI(); + // Grab the track file try { @@ -158,8 +162,6 @@ void World::init() // of karts. m_track->reset(); - m_race_gui = new RaceGUI(); - m_track->startMusic(); if(!history->replayHistory()) history->initRecording(); diff --git a/src/states_screens/race_gui.cpp b/src/states_screens/race_gui.cpp index e253931de..0c0dbae65 100644 --- a/src/states_screens/race_gui.cpp +++ b/src/states_screens/race_gui.cpp @@ -20,23 +20,26 @@ #include "states_screens/race_gui.hpp" +#include "irrlicht.h" +using namespace irr; + #include "audio/sound_manager.hpp" #include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "graphics/material_manager.hpp" #include "input/input.hpp" #include "input/input_manager.hpp" +#include "karts/kart_properties_manager.hpp" #include "race/race_manager.hpp" #include "tracks/track.hpp" #include "utils/constants.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" -#include "irrlicht.h" -using namespace irr; - -const video::SColor white(255,255,255,255); - +/** The constructor is called before anything is attached to the scene node. + * So rendering to a texture can be done here. But world is not yet fully + * created, so only the race manager can be accessed safely. + */ RaceGUI::RaceGUI() { // FIXME: translation problem @@ -52,8 +55,6 @@ RaceGUI::RaceGUI() m_pos_string[9] = "9th"; m_pos_string[10] = "10th"; - gui::IGUIEnvironment *gui_env = irr_driver->getGUI(); - int icon_width=40; int icon_player_width=50; if(UserConfigParams::m_height<600) @@ -62,18 +63,76 @@ RaceGUI::RaceGUI() icon_player_width = 35; } - m_speed_back_icon = material_manager->getMaterial("speedback.png"); - m_speed_fore_icon = material_manager->getMaterial("speedfore.png"); - m_plunger_face = material_manager->getMaterial("plungerface.png"); - + m_speed_meter_icon = material_manager->getMaterial("speedback.png"); + m_speed_bar_icon = material_manager->getMaterial("speedfore.png"); + m_plunger_face = material_manager->getMaterial("plungerface.png"); + createMarkerTexture(); } // RaceGUI //----------------------------------------------------------------------------- RaceGUI::~RaceGUI() { - //FIXME: does all that material stuff need freeing somehow? + irr_driver->removeTexture(m_marker); } // ~Racegui +//----------------------------------------------------------------------------- +/** Creates a texture with the markers for all karts in the current race + * on it. This assumes that nothing is attached to the scene node at + * this stage. + */ +void RaceGUI::createMarkerTexture() +{ + unsigned int n=race_manager->getNumKarts(); + unsigned int npower2 = 1; + // Textures must be power of 2, so + while(npower2>1)-1; + irr_driver->beginRenderToTexture(core::dimension2di(marker_size * npower2, marker_size), + "RaceGUI::markers"); + for(unsigned int i=0; igetNumKarts(); i++) + { + const std::string& kart_name = race_manager->getKartName(i); + const KartProperties *kp = kart_properties_manager->getKart(kart_name); + core::vector2df center((float)((marker_size>>1)+i*marker_size), + (float)(marker_size>>1)); + int count = kp->getShape(); + core::array vertices; + createRegularPolygon(count, (float)radius, center,&vertices); + + video::SColor color = kp->getColor(); + core::array colors; + colors.push_back(color); +#ifdef IRRLICHT_HAS_SUPERTUXKART_POLYGON + irr_driver->getVideoDriver()->draw2DPolygon(vertices, &colors); +#endif + } + m_marker = irr_driver->endRenderToTexture(); + core::dimension2di X = m_marker->getOriginalSize(); +} // createMarkerTexture + +//----------------------------------------------------------------------------- +/** Creates the 2D vertices for a regular polygon. Adopted from Irrlicht. + * \param n Number of vertices to use. + * \param radius Radius of the polygon. + * \param center The center point of the polygon. + * \param v Pointer to the array of vertices. + */ +void RaceGUI::createRegularPolygon(unsigned int n, float radius, + const core::vector2df ¢er, + core::array *v) +{ + float f = 2*M_PI/(float)n; + for (unsigned int i=0; ipush_back(X); + } + +} // createRegularPolygon + //----------------------------------------------------------------------------- /** Called before rendering, so no direct output to the screen can be done * here. @@ -114,16 +173,21 @@ void RaceGUI::drawTimer () //----------------------------------------------------------------------------- #define TRACKVIEW_SIZE 100 -void RaceGUI::drawMap () +void RaceGUI::drawMap() { // arenas currently don't have a map. if(RaceManager::getTrack()->isArena()) return; - const video::ITexture *t=RaceManager::getTrack()->getMiniMap(); + const video::ITexture *mini_map=RaceManager::getTrack()->getMiniMap(); core::rect dest(10, UserConfigParams::m_height-60, 60, UserConfigParams::m_height-10); - core::rect source(core::position2di(0, 0), t->getOriginalSize()); - irr_driver->getVideoDriver()->draw2DImage(t, dest, source, 0, 0, true); + core::rect source(core::position2di(0, 0), mini_map->getOriginalSize()); + //FIXME irr_driver->getVideoDriver()->draw2DImage(mini_map, dest, source, 0, 0, true); + + core::rect dest1( 10, UserConfigParams::m_height-10, + 100, UserConfigParams::m_height-110); + core::rect source1(core::position2di(0, 0), m_marker->getOriginalSize()); + irr_driver->getVideoDriver()->draw2DImage(m_marker, dest, source1, 0, 0, true); return; @@ -140,7 +204,7 @@ void RaceGUI::drawMap () { Kart* kart = RaceManager::getKart(i); if(kart->isEliminated()) continue; // don't draw eliminated kart - glColor3fv ( kart->getColor().toFloat()); + //glColor3fv ( kart->getColor().toFloat()); const Vec3& xyz = kart->getXYZ(); /* If it's a player, draw a bigger sign */ @@ -216,6 +280,7 @@ void RaceGUI::drawPlayerIcons (const KartIconDisplayInfo* info) int w = kart->isPlayerKart() ? ICON_PLAYER_WIDTH : ICON_WIDTH; const core::rect pos(x, y, x+w, y+w); const core::rect rect(core::position2d(0,0), icon->getOriginalSize()); + static const video::SColor white(255, 255, 255, 255); irr_driver->getVideoDriver()->draw2DImage(icon, pos, rect, 0, &white, true); @@ -244,6 +309,7 @@ void RaceGUI::drawPowerupIcons(Kart* player_kart, int offset_x, video::ITexture *t=powerup->getIcon()->getTexture(); core::rect rect(core::position2di(0, 0), t->getOriginalSize()); + static const video::SColor white(255, 255, 255, 255); for ( int i = 0 ; i < n ; i++ ) { core::rect pos(x1+i*30, y1, x1+i*30+nSize, y1+nSize); @@ -272,30 +338,21 @@ void RaceGUI::drawEnergyMeter ( Kart *player_kart, int offset_x, int offset_y, #define LINE(x0,y0,x1,y1, color) video->draw2DLine(core::position2di(x0,y0), \ core::position2di(x1,y1), color) - // FIXME: the original code drew a rectangle, i.e. two lines. This seems to be - // unnecesssary, so it's commented out here // Left side: LINE(x-1, y+1, x-1, y-h-1, black_border); - //LINE(x, y-1, x, y+h+1, black_border); LINE(x, y, x, y-h-2, white_border); - //LINE(x+1, y, x+1, y+h+2, white_border); - + // Right side: LINE(x+w, y+1, x+w, y-h-1, black_border); - //LINE(x+w+1, y-1, x+w+1, y+h+1, black_border); LINE(x+w+1, y, x+w+1, y-h-2, white_border); - //LINE(x+w+2, y, x+w+2, y+h+2, white_border); - + // Bottom LINE(x, y+1, x+w, y+1, black_border); - //LINE(x, y, x+w, y, black_border); LINE(x+1, y, x+w+1, y, white_border); - //LINE(x+1, y+1, x+w+1, y+1, white_border); + // Top LINE(x, y-h, x+w, y-h, black_border); - //LINE(x, y+h+1, x+w, y+h+1, black_border); LINE(x, y-h-1, x+w, y-h-1, white_border); - //LINE(x, y+h+2, x+w, y+h+2, white_border); const int GRADS = (int)(MAX_ITEMS_COLLECTED/5); // each graduation equals 5 items int gh = (int)(h/GRADS); //graduation height @@ -327,21 +384,25 @@ void RaceGUI::drawSpeed(Kart* kart, int offset_x, int offset_y, float ratio_x, float ratio_y ) { - float minRatio = std::min(ratio_x, ratio_y); - const int SPEEDWIDTH=128; - int width = (int)(SPEEDWIDTH*minRatio); - int height = (int)(SPEEDWIDTH*minRatio); - offset_x += (int)((UserConfigParams::m_width-10)*ratio_x) - width; - offset_y += (int)(10*ratio_y); + float minRatio = std::min(ratio_x, ratio_y); + const int SPEEDWIDTH = 128; + int meter_width = (int)(SPEEDWIDTH*minRatio); + int meter_height = (int)(SPEEDWIDTH*minRatio); + offset_x += (int)((UserConfigParams::m_width-10)*ratio_x) - meter_width; + offset_y += (int)(10*ratio_y); + // First draw the meter (i.e. the background which contains the numbers etc. + // ------------------------------------------------------------------------- video::IVideoDriver *video = irr_driver->getVideoDriver(); - video::SColor color(255, 255, 255, 255); - const core::rect pos(offset_x, UserConfigParams::m_height-offset_y-height, - offset_x+width, UserConfigParams::m_height-offset_y); - video::ITexture *t = m_speed_back_icon->getTexture(); - const core::rect rect(core::position2d(0,0), t->getOriginalSize()); - video->draw2DImage(t, pos, rect, 0, &color, true); + const core::rect meter_pos(offset_x, UserConfigParams::m_height-offset_y-meter_height, + offset_x+meter_width, UserConfigParams::m_height-offset_y); + video::ITexture *meter_texture = m_speed_meter_icon->getTexture(); + const core::rect meter_texture_coords(core::position2d(0,0), + meter_texture->getOriginalSize()); + video->draw2DImage(meter_texture, meter_pos, meter_texture_coords, NULL, NULL, true); + // Indicate when the kart is off ground + // ------------------------------------ if ( !kart->isOnGround() ) { static video::SColor color = video::SColor(255, 255, 255, 255); @@ -351,50 +412,48 @@ void RaceGUI::drawSpeed(Kart* kart, int offset_x, int offset_y, UserConfigParams::m_height-(offset_y-(int)(10*minRatio)) ); irr_driver->getRaceFont()->draw(core::stringw("!").c_str(), pos, color); } + const float speed = kart->getSpeed(); - if(speed>0) + if(speed <=0) return; // Nothing to do if speed is negative. + + // Draw the actual speed bar (if the speed is >0) + // ---------------------------------------------- + float speed_ratio = speed/KILOMETERS_PER_HOUR/110.0f; + if(speed_ratio>1) speed_ratio = 1; + + video::ITexture *bar_texture = m_speed_bar_icon->getTexture(); + core::dimension2di bar_size = bar_texture->getOriginalSize(); + core::array tex_coords; // texture coordinates + core::array bar_vertices; // screen coordinates + + tex_coords.push_back(core::vector2di(bar_size.Width, bar_size.Height)); + bar_vertices.push_back(core::vector2df((float)meter_pos.LowerRightCorner.X, + (float)meter_pos.LowerRightCorner.Y)); + tex_coords.push_back(core::vector2di(0,bar_size.Height)); + bar_vertices.push_back(core::vector2df((float)meter_pos.UpperLeftCorner.X, + (float)meter_pos.LowerRightCorner.Y)); + + if(speed_ratio<=0.5f) { - float speed_ratio = speed/KILOMETERS_PER_HOUR/110.0f; - if(speed_ratio>1) speed_ratio = 1; + core::vector2di v0(0, bar_size.Height-(int)(2*(speed_ratio)*bar_size.Height)); + tex_coords.push_back(v0); + bar_vertices.push_back(core::vector2df((float)meter_pos.UpperLeftCorner.X, + (float)meter_pos.LowerRightCorner.Y-speed_ratio*2*meter_height)); + } + else + { + tex_coords.push_back(core::vector2di(0, 0)); + bar_vertices.push_back(core::vector2df((float)offset_x, + (float)(UserConfigParams::m_height-offset_y-meter_height))); - core::rect pos; - video::ITexture *t = m_speed_fore_icon->getTexture(); - core::dimension2di tex_coords=t->getOriginalSize(); - if(speed_ratio<0.5f) - { - pos = core::rect(offset_x, - UserConfigParams::m_height-offset_y-height, - offset_x+width, - UserConfigParams::m_height-offset_y-(int)(height*(1-speed_ratio))); - tex_coords.set(tex_coords.Width, (int)(tex_coords.Height*speed_ratio)); - } - else - { - pos = core::rect(offset_x, - UserConfigParams::m_height-offset_y-height, - (int)(offset_x+width*speed_ratio), - UserConfigParams::m_height-offset_y); - tex_coords.set((int)(tex_coords.Width*speed_ratio), tex_coords.Height); - } - const core::rect rect(core::position2d(0,0), tex_coords); - video->draw2DImage(t, pos, rect, 0, &color, true); -#ifdef XX - - glTexCoord2f(1, 0);glVertex2i(offset_x+width, offset_y); - glTexCoord2f(0, 0);glVertex2i(offset_x, offset_y); - if (speedRatio < 0.5) - { - glTexCoord2f(0, speedRatio*2);glVertex2i(offset_x, (int)(offset_y+width*speedRatio*2)); - } - else - { - glTexCoord2f(0, 1);glVertex2i(offset_x, offset_y+width); - glTexCoord2f((speedRatio-0.5f)*2, 1);glVertex2i((int)(offset_x+height*(speedRatio-0.5f)*2), offset_y+height); - } - - glEnd () ; + core::vector2di v0((int)(2*(speed_ratio-0.5f)*bar_size.Width), 0); + tex_coords.push_back(v0); + bar_vertices.push_back(core::vector2df(offset_x+2*(speed_ratio-0.5f)*meter_width, + (float)(UserConfigParams::m_height-offset_y-meter_height))); + } +#ifdef IRRLICHT_HAS_SUPERTUXKART_POLYGON + irr_driver->getVideoDriver()->draw2DPolygon(bar_vertices, NULL, bar_texture, true, &tex_coords); #endif - } // speed<0 } // drawSpeed //----------------------------------------------------------------------------- @@ -503,7 +562,7 @@ void RaceGUI::drawMusicDescription() const MusicInformation* mi=sound_manager->getCurrentMusic(); if(!mi) return; int y=UserConfigParams::m_height-40; - static video::SColor white = video::SColor(255, 255, 255, 255); + static const video::SColor white = video::SColor(255, 255, 255, 255); gui::IGUIFont* font = irr_driver->getRaceFont(); if(mi->getComposer()!="") { @@ -645,8 +704,8 @@ void RaceGUI::drawStatusText() split_screen_ratio_x, split_screen_ratio_y ); drawEnergyMeter (player_kart, offset_x, offset_y, split_screen_ratio_x, split_screen_ratio_y ); - //drawSpeed (player_kart, offset_x, offset_y, - // split_screen_ratio_x, split_screen_ratio_y ); + drawSpeed (player_kart, offset_x, offset_y, + split_screen_ratio_x, split_screen_ratio_y ); drawLap (info, player_kart, offset_x, offset_y, split_screen_ratio_x, split_screen_ratio_y ); drawAllMessages (player_kart, offset_x, offset_y, @@ -678,7 +737,7 @@ void RaceGUI::drawStatusText() drawMusicDescription(); } - drawMap(); + //drawMap(); drawPlayerIcons(info); } // drawStatusText diff --git a/src/states_screens/race_gui.hpp b/src/states_screens/race_gui.hpp index 02fe91240..c23e2eece 100644 --- a/src/states_screens/race_gui.hpp +++ b/src/states_screens/race_gui.hpp @@ -84,13 +84,18 @@ private: } }; -private: - const char *m_pos_string [11]; - Material *m_speed_back_icon; - Material *m_speed_fore_icon; - Material *m_plunger_face; - typedef std::vector AllMessageType; - AllMessageType m_messages; + const char *m_pos_string [11]; + Material *m_speed_meter_icon; + Material *m_speed_bar_icon; + Material *m_plunger_face; + typedef std::vector AllMessageType; + AllMessageType m_messages; + video::ITexture *m_marker; + + void createMarkerTexture(); + void createRegularPolygon(unsigned int n, float radius, + const core::vector2df ¢er, + core::array *v); /* Display informat on screen */ void drawStatusText (); diff --git a/src/tracks/quad_graph.cpp b/src/tracks/quad_graph.cpp index 3572c9b20..d38d0b036 100644 --- a/src/tracks/quad_graph.cpp +++ b/src/tracks/quad_graph.cpp @@ -406,6 +406,11 @@ video::ITexture *QuadGraph::makeMiniMap(const core::dimension2di &dimension, const video::SColor &fill_color) { irr_driver->beginRenderToTexture(dimension, name); + for(unsigned int i=0; igetNumberOfQuads(); i++) + { +// core::array vertices; +// vertices.push_back(core::vertices + } createMesh(); video::S3DVertex *v = (video::S3DVertex*)m_mesh_buffer->getVertices(); for(unsigned int i=0; igetVertexCount(); i++)