From f95df35dc58e01b99ffddfc4ad394feaa4460b09 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Wed, 4 Jul 2012 00:04:53 +0200 Subject: Multitexturing support - added CImage class for loading/saving images and a simple test for it - added libpng library to build - added Gfx::Texture struct - updated the Gfx::CDevice interface to include new features - implemented the new features in Gfx::CGLDevice --- src/CMakeLists.txt | 9 +- src/common/image.cpp | 221 +++++++++++++++++++ src/common/image.h | 84 ++++++++ src/common/test/CMakeLists.txt | 6 + src/common/test/image_test.cpp | 34 +++ src/graphics/common/device.cpp | 17 ++ src/graphics/common/device.h | 185 +++++++++++++++- src/graphics/common/texture.h | 9 +- src/graphics/opengl/gldevice.cpp | 449 ++++++++++++++++++++++++++++++++++----- src/graphics/opengl/gldevice.h | 33 ++- 10 files changed, 981 insertions(+), 66 deletions(-) create mode 100644 src/common/image.cpp create mode 100644 src/common/image.h create mode 100644 src/common/test/CMakeLists.txt create mode 100644 src/common/test/image_test.cpp (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1be7a59..a02e7b9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,6 +30,7 @@ app/app.cpp app/main.cpp app/system.cpp common/event.cpp +common/image.cpp common/iman.cpp # common/metafile.cpp # common/misc.cpp @@ -150,10 +151,16 @@ set(LIBS ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY} ${OPENGL_LIBRARY} +${PNG_LIBRARIES} #CBot -- not yet WinAPI-independent ) -include_directories(. ${CMAKE_CURRENT_BINARY_DIR}) +include_directories(. ${CMAKE_CURRENT_BINARY_DIR} +${SDL_INCLUDE_DIR} +${SDL_IMAGE_INCLUDE_DIR} +${SDLTTF_INCLUDE_DIR} +${PNG_INCLUDE_DIRS} +) link_directories(${CMAKE_CURRENT_SOURCE_DIR}/CBot) diff --git a/src/common/image.cpp b/src/common/image.cpp new file mode 100644 index 0000000..78834b4 --- /dev/null +++ b/src/common/image.cpp @@ -0,0 +1,221 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// image.cpp + +#include "image.h" + +#include +#include +#include +#include +#include +#include + + +/* <---------------------------------------------------------------> */ + +/* The following code is from savesurf program by Angelo "Encelo" Theodorou + Source: http://encelo.netsons.org/old/sdl/ + The code was refactored and modified slightly to fit the needs. + The copyright information below is kept unchanged. */ + + +/* SaveSurf: an example on how to save a SDLSurface in PNG + Copyright (C) 2006 Angelo "Encelo" Theodorou + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + NOTE: + + This program is part of "Mars, Land of No Mercy" SDL examples, + you can find other examples on http://marsnomercy.org +*/ + +std::string PNG_ERROR = ""; + +void PNGUserError(png_structp ctx, png_const_charp str) +{ + PNG_ERROR = std::string(str); +} + +int PNGColortypeFromSurface(SDL_Surface *surface) +{ + int colortype = PNG_COLOR_MASK_COLOR; /* grayscale not supported */ + + if (surface->format->palette) + colortype |= PNG_COLOR_MASK_PALETTE; + else if (surface->format->Amask) + colortype |= PNG_COLOR_MASK_ALPHA; + + return colortype; +} + +bool PNGSaveSurface(const char *filename, SDL_Surface *surf) +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + int i, colortype; + png_bytep *row_pointers; + + PNG_ERROR = ""; + + /* Opening output file */ + fp = fopen(filename, "wb"); + if (fp == NULL) + { + PNG_ERROR = std::string("Could not open file '") + std::string(filename) + std::string("' for saving"); + return false; + } + + /* Initializing png structures and callbacks */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, PNGUserError, NULL); + if (png_ptr == NULL) + return false; + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + PNG_ERROR = "png_create_info_struct() error!"; + return false; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return false; + } + + png_init_io(png_ptr, fp); + + colortype = PNGColortypeFromSurface(surf); + png_set_IHDR(png_ptr, info_ptr, surf->w, surf->h, 8, colortype, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + /* Writing the image */ + png_write_info(png_ptr, info_ptr); + png_set_packing(png_ptr); + + row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*surf->h); + for (i = 0; i < surf->h; i++) + row_pointers[i] = (png_bytep)(Uint8 *)surf->pixels + i*surf->pitch; + png_write_image(png_ptr, row_pointers); + png_write_end(png_ptr, info_ptr); + + /* Cleaning out... */ + free(row_pointers); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + + return true; +} + +/* <---------------------------------------------------------------> */ + + +CImage::CImage() +{ + m_data = NULL; +} + +CImage::~CImage() +{ + Free(); +} + +bool CImage::IsEmpty() +{ + return m_data == NULL; +} + +void CImage::Free() +{ + if (m_data != NULL) + { + if (m_data->surface != NULL) + { + SDL_FreeSurface(m_data->surface); + m_data->surface = NULL; + } + delete m_data; + m_data = NULL; + } +} + +ImageData* CImage::GetData() +{ + return m_data; +} + +std::string CImage::GetError() +{ + return m_error; +} + +bool CImage::Load(const std::string& fileName) +{ + if (! IsEmpty() ) + Free(); + + m_data = new ImageData(); + + m_error = ""; + + m_data->surface = IMG_Load(fileName.c_str()); + if (m_data->surface == NULL) + { + delete m_data; + m_data = NULL; + + m_error = std::string(IMG_GetError()); + return false; + } + + return true; +} + +bool CImage::SavePNG(const std::string& fileName) +{ + if (IsEmpty()) + { + m_error = "Empty image!"; + return false; + } + + m_error = ""; + + if (! PNGSaveSurface(fileName.c_str(), m_data->surface) ) + { + m_error = PNG_ERROR; + return false; + } + + return true; +} diff --git a/src/common/image.h b/src/common/image.h new file mode 100644 index 0000000..4d86d31 --- /dev/null +++ b/src/common/image.h @@ -0,0 +1,84 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// image.h + +#pragma once + + +#include +#include + + +// Forward declaration without including headers to clutter the code +struct SDL_Surface; + +//! Implementation-specific image data +/** Note that the struct has no destructor and the surface + will not be freed at destruction. */ +struct ImageData +{ + //! SDL surface with image data + SDL_Surface* surface; + + ImageData() { surface = NULL; } +}; + +/** + \class CImage + \brief Image loaded from file + + Wrapper around SDL_Image library to load images. Also contains + function for saving images to PNG. + */ +class CImage +{ +private: + //! Blocked! + CImage(const CImage &other) {} + //! Blocked! + void operator=(const CImage &other) {} + +public: + //! Constructs empty image (with NULL data) + CImage(); + //! Destroys image, calling Free() + virtual ~CImage(); + + //! Frees the allocated image data + void Free(); + + //! Returns whether the image is empty (has NULL data) + bool IsEmpty(); + + //! Returns the image data; if empty - returns NULL + ImageData* GetData(); + + //! Loads an image from the specified file + bool Load(const std::string &fileName); + + //! Saves the image to the specified file in PNG format + bool SavePNG(const std::string &fileName); + + //! Returns the last error + std::string GetError(); + +private: + //! Last encountered error + std::string m_error; + //! Image data + ImageData* m_data; +}; diff --git a/src/common/test/CMakeLists.txt b/src/common/test/CMakeLists.txt new file mode 100644 index 0000000..680116c --- /dev/null +++ b/src/common/test/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 2.8) + +set(CMAKE_BUILD_TYPE debug) +set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0") + +add_executable(image_test ../image.cpp image_test.cpp) diff --git a/src/common/test/image_test.cpp b/src/common/test/image_test.cpp new file mode 100644 index 0000000..0ad1ee2 --- /dev/null +++ b/src/common/test/image_test.cpp @@ -0,0 +1,34 @@ +#include "../image.h" + +#include +#include + +/* For now, just a simple test: loading a file from image + * and saving it to another in PNG. */ + +int main(int argc, char *argv[]) +{ + if (argc != 3) + { + printf("Usage: %s in_image out_image\n", argv[0]); + return 0; + } + + CImage image; + + if (! image.Load(argv[1])) + { + std::string err = image.GetError(); + printf("Error loading '%s': %s\n", err.c_str()); + return 1; + } + + if (! image.SavePNG(argv[2])) + { + std::string err = image.GetError(); + printf("Error saving PNG '%s': %s\n", err.c_str()); + return 2; + } + + return 0; +} diff --git a/src/graphics/common/device.cpp b/src/graphics/common/device.cpp index fcd4318..bb51699 100644 --- a/src/graphics/common/device.cpp +++ b/src/graphics/common/device.cpp @@ -31,3 +31,20 @@ void Gfx::DeviceConfig::LoadDefault() doubleBuf = true; noFrame = false; } + +void Gfx::TextureParams::LoadDefault() +{ + minFilter = Gfx::TEX_MIN_FILTER_NEAREST; + magFilter = Gfx::TEX_MAG_FILTER_NEAREST; + + wrapS = Gfx::TEX_WRAP_REPEAT; + wrapT = Gfx::TEX_WRAP_REPEAT; + + colorOperation = Gfx::TEX_MIX_OPER_MODULATE; + colorArg1 = Gfx::TEX_MIX_ARG_CURRENT; + colorArg2 = Gfx::TEX_MIX_ARG_TEXTURE; + + alphaOperation = Gfx::TEX_MIX_OPER_MODULATE; + alphaArg1 = Gfx::TEX_MIX_ARG_CURRENT; + alphaArg2 = Gfx::TEX_MIX_ARG_TEXTURE; +} diff --git a/src/graphics/common/device.h b/src/graphics/common/device.h index 961fb6b..3382c9a 100644 --- a/src/graphics/common/device.h +++ b/src/graphics/common/device.h @@ -30,6 +30,9 @@ #include +class CImage; + + namespace Gfx { /** @@ -144,6 +147,15 @@ enum CullMode CULL_CCW }; +/** + \enum ShadeModel + \brief Shade model used in rendering */ +enum ShadeModel +{ + SHADE_FLAT, + SHADE_SMOOTH +}; + /** \enum FillMode \brief Polygon fill mode */ @@ -169,6 +181,147 @@ enum PrimitiveType PRIMITIVE_TRIANGLE_STRIP }; +/** + \enum TexMinFilter + \brief Minification texture filter + + Corresponds to OpenGL modes but should translate to DirectX too. */ +enum TexMinFilter +{ + TEX_MIN_FILTER_NEAREST, + TEX_MIN_FILTER_LINEAR, + TEX_MIN_FILTER_NEAREST_MIPMAP_NEAREST, + TEX_MIN_FILTER_LINEAR_MIPMAP_NEAREST, + TEX_MIN_FILTER_NEAREST_MIPMAP_LINEAR, + TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR +}; + +/** + \enum TexMagFilter + \brief Magnification texture filter */ +enum TexMagFilter +{ + TEX_MAG_FILTER_NEAREST, + TEX_MAG_FILTER_LINEAR +}; + +/** + \enum TexWrapMode + \brief Wrapping mode for texture coords */ +enum TexWrapMode +{ + TEX_WRAP_CLAMP, + TEX_WRAP_REPEAT +}; + +/** + \enum TexMixOperation + \brief Multitexture mixing operation + */ +enum TexMixOperation +{ + TEX_MIX_OPER_MODULATE, + TEX_MIX_OPER_ADD +}; + +/** + \enum TexMixArgument + \brief Multitexture mixing argument + */ +enum TexMixArgument +{ + TEX_MIX_ARG_CURRENT, + TEX_MIX_ARG_TEXTURE, + TEX_MIX_ARG_DIFFUSE, + TEX_MIX_ARG_FACTOR +}; + +/** + \enum TextureParams + \brief Parameters for texture creation + */ +struct TextureParams +{ + //! Minification filter + Gfx::TexMinFilter minFilter; + //! Magnification filter + Gfx::TexMagFilter magFilter; + //! Wrap S coord mode + Gfx::TexWrapMode wrapS; + //! Wrap T coord mode + Gfx::TexWrapMode wrapT; + //! Mixing operation done on color values + Gfx::TexMixOperation colorOperation; + //! 1st argument of color operations + Gfx::TexMixArgument colorArg1; + //! 2nd argument of color operations + Gfx::TexMixArgument colorArg2; + //! Mixing operation done on alpha values + Gfx::TexMixOperation alphaOperation; + //! 1st argument of alpha operations + Gfx::TexMixArgument alphaArg1; + //! 2nd argument of alpha operations + Gfx::TexMixArgument alphaArg2; + + //! Constructor; calls LoadDefault() + TextureParams() + { LoadDefault(); } + + //! Loads the default values + void LoadDefault(); +}; + +/* + +Notes for rewriting DirectX code: + +>> SetRenderState() translates to many functions depending on param + +D3DRENDERSTATE_ALPHABLENDENABLE -> SetRenderState() with RENDER_STATE_BLENDING +D3DRENDERSTATE_ALPHAFUNC -> SetAlphaTestFunc() func +D3DRENDERSTATE_ALPHAREF -> SetAlphaTestFunc() ref +D3DRENDERSTATE_ALPHATESTENABLE -> SetRenderState() with RENDER_STATE_ALPHA_TEST +D3DRENDERSTATE_AMBIENT -> SetGlobalAmbient() +D3DRENDERSTATE_CULLMODE -> SetCullMode() +D3DRENDERSTATE_DESTBLEND -> SetBlendFunc() dest blending func +D3DRENDERSTATE_DITHERENABLE -> SetRenderState() with RENDER_STATE_DITHERING +D3DRENDERSTATE_FILLMODE -> SetFillMode() +D3DRENDERSTATE_FOGCOLOR -> SetFogParams() +D3DRENDERSTATE_FOGENABLE -> SetRenderState() with RENDER_STATE_FOG +D3DRENDERSTATE_FOGEND -> SetFogParams() +D3DRENDERSTATE_FOGSTART -> SetFogParams() +D3DRENDERSTATE_FOGVERTEXMODE -> SetFogParams() fog model +D3DRENDERSTATE_LIGHTING -> SetRenderState() with RENDER_STATE_LIGHTING +D3DRENDERSTATE_SHADEMODE -> SetShadeModel() +D3DRENDERSTATE_SPECULARENABLE -> doesn't matter (always enabled) +D3DRENDERSTATE_SRCBLEND -> SetBlendFunc() src blending func +D3DRENDERSTATE_TEXTUREFACTOR -> SetTextureFactor() +D3DRENDERSTATE_ZBIAS -> SetDepthBias() +D3DRENDERSTATE_ZENABLE -> SetRenderState() with RENDER_STATE_DEPTH_TEST +D3DRENDERSTATE_ZFUNC -> SetDepthTestFunc() +D3DRENDERSTATE_ZWRITEENABLE -> SetRenderState() with RENDER_STATE_DEPTH_WRITE + + +>> SetTextureStageState() translates to SetTextureParams() + +Params from enum in struct TextureParams + D3DTSS_ADDRESS -> Gfx::TexWrapMode wrapS, wrapT + D3DTSS_ALPHAARG1 -> Gfx::TexMixArgument alphaArg1 + D3DTSS_ALPHAARG2 -> Gfx::TexMixArgument alphaArg2 + D3DTSS_ALPHAOP -> Gfx::TexMixOperation alphaOperation + D3DTSS_COLORARG1 -> Gfx::TexMixArgument colorArg1 + D3DTSS_COLORARG2 -> Gfx::TexMixArgument colorArg2 + D3DTSS_COLOROP -> Gfx::TexMixOperation colorOperation + D3DTSS_MAGFILTER -> Gfx::TexMagFilter magFilter + D3DTSS_MINFILTER -> Gfx::TexMinFilter minFilter + D3DTSS_TEXCOORDINDEX -> doesn't matter (texture coords are set explicitly by glMultiTexCoordARB*) + +Note that D3DTSS_ALPHAOP or D3DTSS_COLOROP set to D3DTOP_DISABLE must translate to disabling the whole texture stage. +In DirectX, you shouldn't mix enabling one and disabling the other. +Also, if previous stage is disabled in DirectX, the later ones are disabled, too. In OpenGL, that is not the case. + +*/ + /** \class CDevice \brief Abstract interface of graphics device @@ -226,20 +379,33 @@ public: //! Returns the current enable state of light at given index virtual bool GetLightEnabled(int index) = 0; - // TODO: - // virtual Gfx::Texture* CreateTexture(CImage *image) = 0; - // virtual void DestroyTexture(Gfx::Texture *texture) = 0; + //! Creates a texture from image; the image can be safely removed after that + virtual Gfx::Texture* CreateTexture(CImage *image, bool alpha, bool mipMap) = 0; + //! Deletes a given texture, freeing it from video memory + virtual void DestroyTexture(Gfx::Texture *texture) = 0; + //! Deletes all textures created so far + virtual void DestroyAllTextures() = 0; - //! Returns the maximum number of multitexture units + //! Returns the maximum number of multitexture stages virtual int GetMaxTextureCount() = 0; //! Sets the (multi)texture at given index virtual void SetTexture(int index, Gfx::Texture *texture) = 0; //! Returns the (multi)texture at given index virtual Gfx::Texture* GetTexture(int index) = 0; + //! Enables/disables the given texture stage + virtual void SetTextureEnabled(int index, bool enabled) = 0; + //! Returns the current enable state of given texture stage + virtual bool GetTextureEnabled(int index) = 0; - // TODO: - // virtual void GetTextureStageState() = 0; - // virtual void SetTextureStageState() = 0; + //! Sets the current params of texture with given index + virtual void SetTextureParams(int index, const Gfx::TextureParams ¶ms) = 0; + //! Returns the current params of texture with given index + virtual Gfx::TextureParams GetTextureParams(int index) = 0; + + //! Sets the texture factor to the given color value + virtual void SetTextureFactor(Gfx::Color &color) = 0; + //! Returns the current texture factor + virtual Gfx::Color GetTextureFactor() = 0; //! Renders primitive composed of vertices with single texture virtual void DrawPrimitive(Gfx::PrimitiveType type, Gfx::Vertex *vertices, int vertexCount) = 0; @@ -297,6 +463,11 @@ public: //! Returns the current cull mode virtual Gfx::CullMode GetCullMode() = 0; + //! Sets the shade model + virtual void SetShadeModel(Gfx::ShadeModel model) = 0; + //! Returns the current shade model + virtual Gfx::ShadeModel GetShadeModel() = 0; + //! Sets the current fill mode virtual void SetFillMode(Gfx::FillMode mode) = 0; //! Returns the current fill mode diff --git a/src/graphics/common/texture.h b/src/graphics/common/texture.h index ab894db..55d5c70 100644 --- a/src/graphics/common/texture.h +++ b/src/graphics/common/texture.h @@ -20,9 +20,16 @@ namespace Gfx { +/** \struct Texture*/ struct Texture { - // TODO + //! Whether the texture was loaded + bool valid; + //! Id of the texture in graphics engine + unsigned int id; + + Texture() + { valid = false; id = 0; } }; }; // namespace Gfx diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp index d105a93..c6e91e1 100644 --- a/src/graphics/opengl/gldevice.cpp +++ b/src/graphics/opengl/gldevice.cpp @@ -16,6 +16,7 @@ // gldevice.cpp +#include "common/image.h" #include "graphics/opengl/gldevice.h" #include @@ -30,21 +31,13 @@ namespace Gfx { struct GLDevicePrivate { - void (APIENTRY* glMultiTexCoord1fARB)(GLenum target, GLfloat s); void (APIENTRY* glMultiTexCoord2fARB)(GLenum target, GLfloat s, GLfloat t); - void (APIENTRY* glMultiTexCoord3fARB)(GLenum target, GLfloat s, GLfloat t, GLfloat r); - void (APIENTRY* glMultiTexCoord4fARB)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); void (APIENTRY* glActiveTextureARB)(GLenum texture); - void (APIENTRY* glClientActiveTextureARB)(GLenum texture); GLDevicePrivate() { - glMultiTexCoord1fARB = NULL; glMultiTexCoord2fARB = NULL; - glMultiTexCoord3fARB = NULL; - glMultiTexCoord4fARB = NULL; glActiveTextureARB = NULL; - glClientActiveTextureARB = NULL; } }; @@ -71,6 +64,7 @@ Gfx::CGLDevice::CGLDevice() { m_private = new Gfx::GLDevicePrivate(); m_wasInit = false; + m_texturing = false; } @@ -92,18 +86,10 @@ std::string Gfx::CGLDevice::GetError() bool Gfx::CGLDevice::Create() { - m_wasInit = true; - - // TODO: move to functions? - glShadeModel(GL_SMOOTH); - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - + /* First check for extensions + These should be available in standard OpenGL 1.3 + But every distribution is different + So we're loading them dynamically through SDL_GL_GetProcAddress() */ std::string extensions = std::string( (char*) glGetString(GL_EXTENSIONS)); @@ -119,37 +105,58 @@ bool Gfx::CGLDevice::Create() return false; } + m_private->glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) SDL_GL_GetProcAddress("glMultiTexCoord2fARB"); + m_private->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB"); + + if ((m_private->glMultiTexCoord2fARB == NULL) || (m_private->glActiveTextureARB == NULL)) + { + m_error = "Could not load extension functions, even though they seem supported"; + return false; + } + + m_wasInit = true; + + // This is mostly done in all modern hardware by default + // DirectX doesn't even allow the option to turn off perspective correction anymore + // So turn it on permanently + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + // Set just to be sure + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + + m_lights = std::vector(GL_MAX_LIGHTS, Gfx::Light()); + m_lightsEnabled = std::vector (GL_MAX_LIGHTS, false); + int maxTextures = 0; glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextures); - m_textures = std::vector(maxTextures, NULL); - m_lights = std::vector(GL_MAX_LIGHTS, Gfx::Light()); - m_lightsEnabled = std::vector(GL_MAX_LIGHTS, false); - - m_private->glMultiTexCoord1fARB = (PFNGLMULTITEXCOORD1FARBPROC) SDL_GL_GetProcAddress("glMultiTexCoord1fARB"); - m_private->glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) SDL_GL_GetProcAddress("glMultiTexCoord2fARB"); - m_private->glMultiTexCoord3fARB = (PFNGLMULTITEXCOORD3FARBPROC) SDL_GL_GetProcAddress("glMultiTexCoord3fARB"); - m_private->glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC) SDL_GL_GetProcAddress("glMultiTexCoord4fARB"); - m_private->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB"); - m_private->glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glClientActiveTextureARB"); + m_textures = std::vector (maxTextures, NULL); + m_texturesEnabled = std::vector (maxTextures, false); + m_texturesParams = std::vector(maxTextures, Gfx::TextureParams()); return true; } void Gfx::CGLDevice::Destroy() { - m_private->glMultiTexCoord1fARB = NULL; m_private->glMultiTexCoord2fARB = NULL; - m_private->glMultiTexCoord3fARB = NULL; - m_private->glMultiTexCoord4fARB = NULL; m_private->glActiveTextureARB = NULL; - m_private->glClientActiveTextureARB = NULL; // Delete the remaining textures - std::set::iterator it; - for (it = m_allTextures.begin(); it != m_allTextures.end(); ++it) - delete *it; - m_allTextures.clear(); + // Should not be strictly necessary, but just in case + DestroyAllTextures(); + + m_lights.clear(); + m_lightsEnabled.clear(); + + m_textures.clear(); + m_texturesEnabled.clear(); + m_texturesParams.clear(); m_wasInit = false; } @@ -177,7 +184,7 @@ void Gfx::CGLDevice::Clear() void Gfx::CGLDevice::SetTransform(Gfx::TransformType type, const Math::Matrix &matrix) { - if (type == Gfx::TRANSFORM_WORLD) + if (type == Gfx::TRANSFORM_WORLD) { m_worldMat = matrix; m_modelviewMat = Math::MultiplyMatrices(m_worldMat, m_viewMat); @@ -205,7 +212,7 @@ void Gfx::CGLDevice::SetTransform(Gfx::TransformType type, const Math::Matrix &m const Math::Matrix& Gfx::CGLDevice::GetTransform(Gfx::TransformType type) { - if (type == Gfx::TRANSFORM_WORLD) + if (type == Gfx::TRANSFORM_WORLD) return m_worldMat; else if (type == Gfx::TRANSFORM_VIEW) return m_viewMat; @@ -219,7 +226,7 @@ const Math::Matrix& Gfx::CGLDevice::GetTransform(Gfx::TransformType type) void Gfx::CGLDevice::MultiplyTransform(Gfx::TransformType type, const Math::Matrix &matrix) { - if (type == Gfx::TRANSFORM_WORLD) + if (type == Gfx::TRANSFORM_WORLD) { m_worldMat = Math::MultiplyMatrices(m_worldMat, matrix); m_modelviewMat = Math::MultiplyMatrices(m_worldMat, m_viewMat); @@ -306,7 +313,7 @@ const Gfx::Light& Gfx::CGLDevice::GetLight(int index) void Gfx::CGLDevice::SetLightEnabled(int index, bool enabled) { assert(index >= 0); - assert(index < (int)m_lightsEnabled.size()); + assert(index < (int)m_lights.size()); m_lightsEnabled[index] = enabled; @@ -321,11 +328,102 @@ bool Gfx::CGLDevice::GetLightEnabled(int index) return m_lightsEnabled[index]; } +Gfx::Texture* Gfx::CGLDevice::CreateTexture(CImage *image, bool alpha, bool mipMap) +{ + Gfx::Texture *result = new Gfx::Texture(); + + // Texturing must be enabled, so enable 1st texture stage + m_private->glActiveTextureARB(GL_TEXTURE0_ARB); + glEnable(GL_TEXTURE_2D); + + glGenTextures(1, &result->id); + glBindTexture(GL_TEXTURE_2D, result->id); + + GLenum sourceFormat = 0; + if (alpha) + sourceFormat = GL_RGBA; + else + sourceFormat = GL_RGB; + + ImageData *data = image->GetData(); + if (data == NULL) + return NULL; + + if (mipMap) + { + gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, data->surface->w, + data->surface->h, sourceFormat, GL_UNSIGNED_BYTE, + data->surface->pixels); + } + else + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data->surface->w, data->surface->h, + 0, sourceFormat, GL_UNSIGNED_BYTE, data->surface->pixels); + } + + // Restore previous setup of 1st texture stage + RestoreTextureStage(0); + + return result; +} + +void Gfx::CGLDevice::DestroyTexture(Gfx::Texture *texture) +{ + std::set::iterator it = m_allTextures.find(texture); + if (it != m_allTextures.end()) + m_allTextures.erase(it); + + glDeleteTextures(1, &texture->id); +} + +void Gfx::CGLDevice::DestroyAllTextures() +{ + std::set allCopy = m_allTextures; + std::set::iterator it; + for (it = allCopy.begin(); it != allCopy.end(); ++it) + { + DestroyTexture(*it); + delete *it; + } +} + int Gfx::CGLDevice::GetMaxTextureCount() { return m_textures.size(); } +/** + If \a texture is \c NULL or invalid, unbinds the given texture. + If valid, binds the texture and enables the given texture stage. + The setting is remembered, even if texturing is disabled at the moment. */ +void Gfx::CGLDevice::SetTexture(int index, Gfx::Texture *texture) +{ + assert(index >= 0); + assert(index < (int)m_textures.size()); + + // Enable the given texture stage + m_private->glActiveTextureARB(GL_TEXTURE0_ARB + index); + glEnable(GL_TEXTURE_2D); + + if ((texture == NULL) || (! texture->valid)) + { + glBindTexture(GL_TEXTURE_2D, 0); // unbind texture + m_textures[index] = NULL; // remember the changes + } + else + { + glBindTexture(GL_TEXTURE_2D, texture->id); // bind the texture + m_textures[index] = texture; // remember the changes + SetTextureParams(index, m_texturesParams[index]); // texture params need to be re-set for the new texture + } + + // Disable the stage if it is set so + if ( (! m_texturing) || (! m_texturesEnabled[index]) ) + glDisable(GL_TEXTURE_2D); +} + +/** + Returns the previously assigned texture or \c NULL if the given stage is not enabled. */ Gfx::Texture* Gfx::CGLDevice::GetTexture(int index) { assert(index >= 0); @@ -334,14 +432,224 @@ Gfx::Texture* Gfx::CGLDevice::GetTexture(int index) return m_textures[index]; } -void Gfx::CGLDevice::SetTexture(int index, Gfx::Texture *texture) +void Gfx::CGLDevice::SetTextureEnabled(int index, bool enabled) { assert(index >= 0); assert(index < (int)m_textures.size()); - m_textures[index] = texture; + m_texturesEnabled[index] = enabled; - // TODO + m_private->glActiveTextureARB(GL_TEXTURE0_ARB + index); + if (enabled) + glEnable(GL_TEXTURE_2D); + else + glDisable(GL_TEXTURE_2D); +} + +bool Gfx::CGLDevice::GetTextureEnabled(int index) +{ + assert(index >= 0); + assert(index < (int)m_textures.size()); + + return m_texturesEnabled[index]; +} + +/** + Sets the texture parameters for the given texture stage. + If the given texture was not set (bound) yet, nothing happens. + The settings are remembered, even if texturing is disabled at the moment. */ +void Gfx::CGLDevice::SetTextureParams(int index, const Gfx::TextureParams ¶ms) +{ + assert(index >= 0); + assert(index < (int)m_textures.size()); + + // Remember the settings + m_texturesParams[index] = params; + + // Enable the given stage + m_private->glActiveTextureARB(GL_TEXTURE0_ARB + index); + glEnable(GL_TEXTURE_2D); + + GLint minF = 0; + if (params.minFilter == Gfx::TEX_MIN_FILTER_NEAREST) minF = GL_NEAREST; + else if (params.minFilter == Gfx::TEX_MIN_FILTER_LINEAR) minF = GL_LINEAR; + else if (params.minFilter == Gfx::TEX_MIN_FILTER_NEAREST_MIPMAP_NEAREST) minF = GL_NEAREST_MIPMAP_NEAREST; + else if (params.minFilter == Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_NEAREST) minF = GL_LINEAR_MIPMAP_NEAREST; + else if (params.minFilter == Gfx::TEX_MIN_FILTER_NEAREST_MIPMAP_LINEAR) minF = GL_NEAREST_MIPMAP_LINEAR; + else if (params.minFilter == Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR) minF = GL_LINEAR_MIPMAP_LINEAR; + else assert(false); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minF); + + GLint magF = 0; + if (params.magFilter == Gfx::TEX_MAG_FILTER_NEAREST) magF = GL_NEAREST; + else if (params.magFilter == Gfx::TEX_MAG_FILTER_LINEAR) magF = GL_LINEAR; + else assert(false); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magF); + + if (params.wrapS == Gfx::TEX_WRAP_CLAMP) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + else if (params.wrapS == Gfx::TEX_WRAP_REPEAT) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + else assert(false); + + if (params.wrapT == Gfx::TEX_WRAP_CLAMP) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + else if (params.wrapT == Gfx::TEX_WRAP_REPEAT) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + else assert(false); + + + // Selection of operation and arguments + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + // Color operation + if (params.colorOperation == Gfx::TEX_MIX_OPER_MODULATE) + glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_RGB, GL_MODULATE); + else if (params.colorOperation == Gfx::TEX_MIX_OPER_ADD) + glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_RGB, GL_ADD); + else assert(false); + + // Color arg1 + if (params.colorArg1 == Gfx::TEX_MIX_ARG_CURRENT) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); // that's right - stupid D3D enum values + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + } + else if (params.colorArg1 == Gfx::TEX_MIX_ARG_TEXTURE) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + } + else if (params.colorArg1 == Gfx::TEX_MIX_ARG_DIFFUSE) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR); // here as well + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + } + else assert(false); + + // Color arg2 + if (params.colorArg2 == Gfx::TEX_MIX_ARG_CURRENT) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + } + else if (params.colorArg2 == Gfx::TEX_MIX_ARG_TEXTURE) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + } + else if (params.colorArg2 == Gfx::TEX_MIX_ARG_DIFFUSE) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + } + else assert(false); + + // Alpha operation + if (params.alphaOperation == Gfx::TEX_MIX_OPER_MODULATE) + glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_ALPHA, GL_MODULATE); + else if (params.alphaOperation == Gfx::TEX_MIX_OPER_ADD) + glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_ALPHA, GL_ADD); + else assert(false); + + // Alpha arg1 + if (params.alphaArg1 == Gfx::TEX_MIX_ARG_CURRENT) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + } + else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_TEXTURE) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + } + else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_DIFFUSE) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + } + else assert(false); + + // Alpha arg2 + if (params.alphaArg2 == Gfx::TEX_MIX_ARG_CURRENT) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + } + else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_TEXTURE) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + } + else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_DIFFUSE) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + } + else assert(false); + + // Disable the stage if it is set so + if ( (! m_texturing) || (! m_texturesEnabled[index]) ) + glDisable(GL_TEXTURE_2D); +} + +Gfx::TextureParams Gfx::CGLDevice::GetTextureParams(int index) +{ + assert(index >= 0); + assert(index < (int)m_textures.size()); + + return m_texturesParams[index]; +} + +void Gfx::CGLDevice::SetTextureFactor(Gfx::Color &color) +{ + // Needs to be set for all texture stages + for (int index = 0; index < (int)m_textures.size(); ++index) + { + // Activate stage + m_private->glActiveTextureARB(GL_TEXTURE0_ARB + index); + glEnable(GL_TEXTURE_2D); + + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color.Array()); + + // Disable the stage if it is set so + if ( (! m_texturing) || (! m_texturesEnabled[index]) ) + glDisable(GL_TEXTURE_2D); + } +} + +Gfx::Color Gfx::CGLDevice::GetTextureFactor() +{ + // Get from 1st stage (should be the same for all stages) + m_private->glActiveTextureARB(GL_TEXTURE0_ARB); + glEnable(GL_TEXTURE_2D); + + GLfloat color[4] = { 0.0f }; + glGetTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); + + // Disable the 1st stage if it is set so + if ( (! m_texturing) || (! m_texturesEnabled[0]) ) + glDisable(GL_TEXTURE_2D); + + return Gfx::Color(color[0], color[1], color[2], color[3]); +} + +void Gfx::CGLDevice::RestoreTextureStage(int index) +{ + // Ensure that we're working with the right stage + m_private->glActiveTextureARB(GL_TEXTURE0_ARB + index); + glEnable(GL_TEXTURE_2D); + + if (m_textures[index] != NULL) + glBindTexture(GL_TEXTURE_2D, m_textures[index]->id); // bind to the previous texture + else + glBindTexture(GL_TEXTURE_2D, 0); // unbind + + // Disable the stage if it is set so + if ( (! m_texturing) || (! m_texturesEnabled[index]) ) + glDisable(GL_TEXTURE_2D); } void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, Vertex *vertices, int vertexCount) @@ -374,7 +682,7 @@ void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, Gfx::VertexCol *vert for (int i = 0; i < vertexCount; ++i) { - // TODO: specular? + // TODO: specular through EXT_separate_specular_color? glColor4fv((GLfloat*)vertices[i].color.Array()); glTexCoord2fv((GLfloat*)vertices[i].texCoord.Array()); glVertex3fv((GLfloat*)vertices[i].coord.Array()); @@ -395,8 +703,8 @@ void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, VertexTex2 *vertices for (int i = 0; i < vertexCount; ++i) { glNormal3fv((GLfloat*) vertices[i].normal.Array()); - // TODO glMultiTexCoord2fARB(GL_TEXTURE0_ARB, vertices[i].texCoord.x, vertices[i].texCoord.y); - // TODO glMultiTexCoord2fARB(GL_TEXTURE1_ARB, vertices[i].texCoord2.x, vertices[i].texCoord2.y); + m_private->glMultiTexCoord2fARB(GL_TEXTURE0_ARB, vertices[i].texCoord.x, vertices[i].texCoord.y); + m_private->glMultiTexCoord2fARB(GL_TEXTURE1_ARB, vertices[i].texCoord2.x, vertices[i].texCoord2.y); glVertex3fv((GLfloat*) vertices[i].coord.Array()); } @@ -412,14 +720,26 @@ void Gfx::CGLDevice::SetRenderState(Gfx::RenderState state, bool enabled) } else if (state == RENDER_STATE_TEXTURING) { + m_texturing = enabled; + if (enabled) { - glEnable(GL_TEXTURE_2D); - // TODO multitexture + // All enabled multitexture stages have to be enabled + for (int index = 0; index < (int)m_textures.size(); ++index) + { + m_private->glActiveTextureARB(GL_TEXTURE0_ARB + index); + if (m_texturesEnabled[index]) + glEnable(GL_TEXTURE_2D); + } } else { - glDisable(GL_TEXTURE_2D); + // All multitexture stages have to be disabled + for (int index = 0; index < (int)m_textures.size(); ++index) + { + m_private->glActiveTextureARB(GL_TEXTURE0_ARB + index); + glDisable(GL_TEXTURE_2D); + } } return; } @@ -445,12 +765,14 @@ void Gfx::CGLDevice::SetRenderState(Gfx::RenderState state, bool enabled) bool Gfx::CGLDevice::GetRenderState(Gfx::RenderState state) { + if (state == RENDER_STATE_TEXTURING) + return m_texturing; + GLenum flag = 0; switch (state) { case Gfx::RENDER_STATE_DEPTH_WRITE: flag = GL_DEPTH_WRITEMASK; break; - case Gfx::RENDER_STATE_TEXTURING: flag = GL_TEXTURE_2D; break; case Gfx::RENDER_STATE_LIGHTING: flag = GL_DEPTH_WRITEMASK; break; case Gfx::RENDER_STATE_BLENDING: flag = GL_BLEND; break; case Gfx::RENDER_STATE_FOG: flag = GL_FOG; break; @@ -602,7 +924,7 @@ void Gfx::CGLDevice::SetClearColor(Gfx::Color color) Gfx::Color Gfx::CGLDevice::GetClearColor() { - float color[4] = { 0.0f }; + GLfloat color[4] = { 0.0f }; glGetFloatv(GL_COLOR_CLEAR_VALUE, color); return Gfx::Color(color[0], color[1], color[2], color[3]); } @@ -614,7 +936,7 @@ void Gfx::CGLDevice::SetGlobalAmbient(Gfx::Color color) Gfx::Color Gfx::CGLDevice::GetGlobalAmbient() { - float color[4] = { 0.0f }; + GLfloat color[4] = { 0.0f }; glGetFloatv(GL_LIGHT_MODEL_AMBIENT, color); return Gfx::Color(color[0], color[1], color[2], color[3]); } @@ -662,6 +984,23 @@ Gfx::CullMode Gfx::CGLDevice::GetCullMode() return Gfx::CULL_CW; } +void Gfx::CGLDevice::SetShadeModel(Gfx::ShadeModel model) +{ + if (model == Gfx::SHADE_FLAT) glShadeModel(GL_FLAT); + else if (model == Gfx::SHADE_SMOOTH) glShadeModel(GL_SMOOTH); + else assert(false); +} + +Gfx::ShadeModel Gfx::CGLDevice::GetShadeModel() +{ + GLenum flag = 0; + glGetIntegerv(GL_SHADE_MODEL, (GLint*)&flag); + if (flag == GL_FLAT) return Gfx::SHADE_FLAT; + else if (flag == GL_SMOOTH) return Gfx::SHADE_SMOOTH; + else assert(false); + return Gfx::SHADE_FLAT; +} + void Gfx::CGLDevice::SetFillMode(Gfx::FillMode mode) { if (mode == Gfx::FILL_POINT) glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); @@ -677,6 +1016,6 @@ Gfx::FillMode Gfx::CGLDevice::GetFillMode() if (flag == GL_POINT) return Gfx::FILL_POINT; else if (flag == GL_LINE) return Gfx::FILL_LINES; else if (flag == GL_FILL) return Gfx::FILL_FILL; - else assert(false); + else assert(false); return Gfx::FILL_POINT; } diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h index 298eb56..aa5dd04 100644 --- a/src/graphics/opengl/gldevice.h +++ b/src/graphics/opengl/gldevice.h @@ -97,9 +97,21 @@ public: virtual void SetLightEnabled(int index, bool enabled); virtual bool GetLightEnabled(int index); + virtual Gfx::Texture* CreateTexture(CImage *image, bool alpha, bool mipMap); + virtual void DestroyTexture(Gfx::Texture *texture); + virtual void DestroyAllTextures(); + virtual int GetMaxTextureCount(); - virtual void SetTexture(int index, Gfx::Texture *texture); + virtual void SetTexture(int index, Gfx::Texture *texture); virtual Gfx::Texture* GetTexture(int index); + virtual void SetTextureEnabled(int index, bool enabled); + virtual bool GetTextureEnabled(int index); + + virtual void SetTextureParams(int index, const Gfx::TextureParams ¶ms); + virtual Gfx::TextureParams GetTextureParams(int index); + + virtual void SetTextureFactor(Gfx::Color &color); + virtual Gfx::Color GetTextureFactor(); virtual void DrawPrimitive(Gfx::PrimitiveType type, Vertex *vertices, int vertexCount); virtual void DrawPrimitive(Gfx::PrimitiveType type, Gfx::VertexCol *vertices, int vertexCount); @@ -133,6 +145,9 @@ public: virtual void SetCullMode(Gfx::CullMode mode); virtual Gfx::CullMode GetCullMode(); + virtual void SetShadeModel(Gfx::ShadeModel model); + virtual Gfx::ShadeModel GetShadeModel(); + virtual void SetFillMode(Gfx::FillMode mode) ; virtual Gfx::FillMode GetFillMode(); @@ -143,6 +158,7 @@ private: bool m_wasInit; //! Last encountered error std::string m_error; + //! Current world matrix Math::Matrix m_worldMat; //! Current view matrix @@ -151,16 +167,29 @@ private: Math::Matrix m_modelviewMat; //! Current projection matrix Math::Matrix m_projectionMat; + //! The current material Gfx::Material m_material; + //! Current lights std::vector m_lights; //! Current lights enable status std::vector m_lightsEnabled; - //! Current textures + + //! Whether texturing is enabled in general + bool m_texturing; + //! Current textures; \c NULL value means unassigned std::vector m_textures; + //! Current texture stages enable status + std::vector m_texturesEnabled; + //! Current texture params + std::vector m_texturesParams; + //! Set of all created textures std::set m_allTextures; + + //! Restores the state of given texture stage to the previously saved settings + void RestoreTextureStage(int index); }; }; // namespace Gfx -- cgit v1.2.3-1-g7c22