diff options
Diffstat (limited to 'src/graphics')
64 files changed, 9389 insertions, 1993 deletions
diff --git a/src/graphics/common/README.txt b/src/graphics/common/README.txt deleted file mode 100644 index 495a453..0000000 --- a/src/graphics/common/README.txt +++ /dev/null @@ -1,5 +0,0 @@ -src/graphics/common - -Universal structs and classes used in graphics engine - -Concrete implementation in OpenGL is in graphics/opengl directory. diff --git a/src/graphics/common/camera.cpp b/src/graphics/common/camera.cpp deleted file mode 100644 index 9990d01..0000000 --- a/src/graphics/common/camera.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * 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/. - -// camera.cpp - -#include "graphics/common/camera.h" - - -// TODO implementation diff --git a/src/graphics/common/camera.h b/src/graphics/common/camera.h deleted file mode 100644 index f17ecef..0000000 --- a/src/graphics/common/camera.h +++ /dev/null @@ -1,273 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * 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/. - -// camera.h - -#pragma once - -#include "engine.h" -#include "common/event.h" - - -class CInstanceManager; -class Gfx::CEngine; -class Gfx::CTerrain; -class Gfx::CWater; -class CObject; - -namespace Gfx { - - -enum CameraType -{ - CAMERA_NULL = 0, // camera undefined - CAMERA_FREE = 1, // camera free (never in principle) - CAMERA_EDIT = 2, // camera while editing a program - CAMERA_ONBOARD = 3, // camera on board a robot - CAMERA_BACK = 4, // camera behind a robot - CAMERA_FIX = 5, // static camera following robot - CAMERA_EXPLO = 6, // camera steady after explosion - CAMERA_SCRIPT = 7, // camera during a film script - CAMERA_INFO = 8, // camera for displaying information - CAMERA_VISIT = 9, // visit instead of an error - CAMERA_DIALOG = 10, // camera for dialogue - CAMERA_PLANE = 11, // static camera height -}; - -enum CameraSmooth -{ - CS_NONE = 0, // sharp - CS_NORM = 1, // normal - CS_HARD = 2, // hard - CS_SPEC = 3, // special -}; - -enum CenteringPhase -{ - CP_NULL = 0, - CP_START = 1, - CP_WAIT = 2, - CP_STOP = 3, -}; - -enum CameraEffect -{ - CE_NULL = 0, // no effect - CE_TERRAFORM = 1, // digging in - CE_CRASH = 2, // Vehicle driving is severely - CE_EXPLO = 3, // explosion - CE_SHOT = 4, // not mortal shot - CE_VIBRATION = 5, // vibration during construction - CE_PET = 6, // spleen reactor -}; - -enum OverEffect -{ - OE_NULL = 0, // no effect - OE_BLOOD = 1, // flash red - OE_FADEINw = 2, // white -> nothing - OE_FADEOUTw = 3, // nothing -> white - OE_FADEOUTb = 4, // nothing -> blue - OE_BLITZ = 5, // lightning -}; - - - -class CCamera { - - public: - CCamera(CInstanceManager* iMan); - ~CCamera(); - - bool EventProcess(const Event &event); - - void Init(Math::Vector eye, Math::Vector lookat, float delay); - - void SetObject(CObject* object); - CObject* RetObject(); - - void SetType(CameraType type); - CameraType RetType(); - - void SetSmooth(CameraSmooth type); - CameraSmooth RetSmoth(); - - void SetDist(float dist); - float RetDist(); - - void SetFixDirection(float angle); - float RetFixDirection(); - - void SetRemotePan(float value); - float RetRemotePan(); - - void SetRemoteZoom(float value); - float RetRemoteZoom(); - - void StartVisit(Math::Vector goal, float dist); - void StopVisit(); - - void RetCamera(Math::Vector &eye, Math::Vector &lookat); - - bool StartCentering(CObject *object, float angleH, float angleV, float dist, float time); - bool StopCentering(CObject *object, float time); - void AbortCentering(); - - void FlushEffect(); - void StartEffect(CameraEffect effect, Math::Vector pos, float force); - - void FlushOver(); - void SetOverBaseColor(Gfx::Color color); - void StartOver(OverEffect effect, Math::Vector pos, float force); - - void FixCamera(); - void SetScriptEye(Math::Vector eye); - void SetScriptLookat(Math::Vector lookat); - - void SetEffect(bool bEnable); - void SetCameraScroll(bool bScroll); - void SetCameraInvertX(bool bInvert); - void SetCameraInvertY(bool bInvert); - - float RetMotorTurn(); - Gfx::MouseType RetMouseDef(Math::Point pos); - -protected: - bool EventMouseMove(const Event &event); - void EventMouseWheel(int dir); - bool EventFrame(const Event &event); - bool EventFrameFree(const Event &event); - bool EventFrameEdit(const Event &event); - bool EventFrameDialog(const Event &event); - bool EventFrameBack(const Event &event); - bool EventFrameFix(const Event &event); - bool EventFrameExplo(const Event &event); - bool EventFrameOnBoard(const Event &event); - bool EventFrameInfo(const Event &event); - bool EventFrameVisit(const Event &event); - bool EventFrameScript(const Event &event); - - void SetViewTime(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, float rTime); - bool IsCollision(Math::Vector &eye, Math::Vector lookat); - bool IsCollisionBack(Math::Vector &eye, Math::Vector lookat); - bool IsCollisionFix(Math::Vector &eye, Math::Vector lookat); - - Math::Vector ExcludeTerrain(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV); - Math::Vector ExcludeObject(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV); - - void SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, const Math::Vector &up); - void EffectFrame(const Event &event); - void OverFrame(const Event &event); - -protected: - CInstanceManager* m_iMan; - Gfx::CEngine* m_engine; - CTerrain* m_terrain; - CWater* m_water; - - CameraType m_type; // the type of camera (CAMERA *) - CameraSmooth m_smooth; // type of smoothing - CObject* m_cameraObj; // object linked to the camera - - float m_eyeDistance; // distance between the eyes - float m_initDelay; // time of initial centering - - Math::Vector m_actualEye; // current eye - Math::Vector m_actualLookat; // aim current - Math::Vector m_finalEye; // final eye - Math::Vector m_finalLookat; // aim final - Math::Vector m_normEye; // normal eye - Math::Vector m_normLookat; // aim normal - float m_focus; - - bool m_bRightDown; - Math::Point m_rightPosInit; - Math::Point m_rightPosCenter; - Math::Point m_rightPosMove; - - Math::Vector m_eyePt; // CAMERA_FREE: eye - float m_directionH; // CAMERA_FREE: horizontal direction - float m_directionV; // CAMERA_FREE: vertical direction - float m_heightEye; // CAMERA_FREE: height above the ground - float m_heightLookat; // CAMERA_FREE: height above the ground - float m_speed; // CAMERA_FREE: speed of movement - - float m_backDist; // CAMERA_BACK: distance - float m_backMin; // CAMERA_BACK: distance minimal - float m_addDirectionH; // CAMERA_BACK: additional direction - float m_addDirectionV; // CAMERA_BACK: additional direction - bool m_bTransparency; - - float m_fixDist; // CAMERA_FIX: distance - float m_fixDirectionH; // CAMERA_FIX: direction - float m_fixDirectionV; // CAMERA_FIX: direction - - Math::Vector m_visitGoal; // CAMERA_VISIT: target position - float m_visitDist; // CAMERA_VISIT: distance - float m_visitTime; // CAMERA_VISIT: relative time - CameraType m_visitType; // CAMERA_VISIT: initial type - float m_visitDirectionH; // CAMERA_VISIT: direction - float m_visitDirectionV; // CAMERA_VISIT: direction - - float m_editHeight; // CAMERA_EDIT: height - - float m_remotePan; - float m_remoteZoom; - - Math::Point m_mousePos; - float m_mouseDirH; - float m_mouseDirV; - float m_mouseMarging; - - float m_motorTurn; - - CenteringPhase m_centeringPhase; - float m_centeringAngleH; - float m_centeringAngleV; - float m_centeringDist; - float m_centeringCurrentH; - float m_centeringCurrentV; - float m_centeringTime; - float m_centeringProgress; - - CameraEffect m_effectType; - Math::Vector m_effectPos; - float m_effectForce; - float m_effectProgress; - Math::Vector m_effectOffset; - - OverEffect m_overType; - float m_overForce; - float m_overTime; - Gfx::Color m_overColorBase; - Gfx::Color m_overColor; - int m_overMode; - float m_overFadeIn; - float m_overFadeOut; - - Math::Vector m_scriptEye; - Math::Vector m_scriptLookat; - - bool m_bEffect; // shocks if explosion? - bool m_bCameraScroll; // scroll in the edges? - bool m_bCameraInvertX; // X inversion in the edges? - bool m_bCameraInvertY; // Y inversion in the edges? - -}; - - -}; // namespace Gfx diff --git a/src/graphics/common/color.cpp b/src/graphics/common/color.cpp deleted file mode 100644 index dd502f9..0000000 --- a/src/graphics/common/color.cpp +++ /dev/null @@ -1,150 +0,0 @@ -// * 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/. - -// color.cpp - -#include "graphics/common/color.h" - -#include "math/func.h" - - -// Returns the color corresponding long. - -long Gfx::RetColor(float intensity) -{ - long color; - - if ( intensity <= 0.0f ) return 0x00000000; - if ( intensity >= 1.0f ) return 0xffffffff; - - color = (int)(intensity*255.0f)<<24; - color |= (int)(intensity*255.0f)<<16; - color |= (int)(intensity*255.0f)<<8; - color |= (int)(intensity*255.0f); - - return color; -} - -// Returns the color corresponding long. - -long Gfx::RetColor(Gfx::Color intensity) -{ - long color; - - color = (int)(intensity.a*255.0f)<<24; - color |= (int)(intensity.r*255.0f)<<16; - color |= (int)(intensity.g*255.0f)<<8; - color |= (int)(intensity.b*255.0f); - - return color; -} - -// Returns the color corresponding Color. - -Gfx::Color Gfx::RetColor(long intensity) -{ - Gfx::Color color; - - color.r = (float)((intensity>>16)&0xff)/256.0f; - color.g = (float)((intensity>>8 )&0xff)/256.0f; - color.b = (float)((intensity>>0 )&0xff)/256.0f; - color.a = (float)((intensity>>24)&0xff)/256.0f; - - return color; -} - - -// RGB to HSV conversion. - -void Gfx::RGB2HSV(Gfx::Color src, Gfx::ColorHSV &dest) -{ - float min, max, delta; - - min = Math::Min(src.r, src.g, src.b); - max = Math::Max(src.r, src.g, src.b); - - dest.v = max; // intensity - - if ( max == 0.0f ) - { - dest.s = 0.0f; // saturation - dest.h = 0.0f; // undefined color! - } - else - { - delta = max-min; - dest.s = delta/max; // saturation - - if ( src.r == max ) // between yellow & magenta - { - dest.h = (src.g-src.b)/delta; - } - else if ( src.g == max ) // between cyan & yellow - { - dest.h = 2.0f+(src.b-src.r)/delta; - } - else // between magenta & cyan - { - dest.h = 4.0f+(src.r-src.g)/delta; - } - - dest.h *= 60.0f; // in degrees - if ( dest.h < 0.0f ) dest.h += 360.0f; - dest.h /= 360.0f; // 0..1 - } -} - -// HSV to RGB conversion. - -void Gfx::HSV2RGB(Gfx::ColorHSV src, Gfx::Color &dest) -{ - int i; - float f,v,p,q,t; - - src.h = Math::Norm(src.h)*360.0f; - src.s = Math::Norm(src.s); - src.v = Math::Norm(src.v); - - if ( src.s == 0.0f ) // zero saturation? - { - dest.r = src.v; - dest.g = src.v; - dest.b = src.v; // gray - } - else - { - if ( src.h == 360.0f ) src.h = 0.0f; - src.h /= 60.0f; - i = (int)src.h; // integer part (0 .. 5) - f = src.h-i; // fractional part - - v = src.v; - p = src.v*(1.0f-src.s); - q = src.v*(1.0f-(src.s*f)); - t = src.v*(1.0f-(src.s*(1.0f-f))); - - switch (i) - { - case 0: dest.r=v; dest.g=t; dest.b=p; break; - case 1: dest.r=q; dest.g=v; dest.b=p; break; - case 2: dest.r=p; dest.g=v; dest.b=t; break; - case 3: dest.r=p; dest.g=q; dest.b=v; break; - case 4: dest.r=t; dest.g=p; dest.b=v; break; - case 5: dest.r=v; dest.g=p; dest.b=q; break; - } - } -} - diff --git a/src/graphics/common/color.h b/src/graphics/common/color.h deleted file mode 100644 index 12f008f..0000000 --- a/src/graphics/common/color.h +++ /dev/null @@ -1,50 +0,0 @@ -// * 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/. - -// color.h - -#pragma once - - -namespace Gfx { - -struct Color -{ - float r, g, b, a; - - Color(float aR = 0.0f, float aG = 0.0f, float aB = 0.0f, float aA = 0.0f) - : r(aR), g(aG), b(aB), a(aA) {} -}; - - -struct ColorHSV -{ - float h, s, v; - - ColorHSV(float aH = 0.0f, float aS = 0.0f, float aV = 0.0f) - : h(aH), s(aS), v(aV) {} -}; - - -long RetColor(float intensity); -long RetColor(Color intensity); -Color RetColor(long intensity); - -void RGB2HSV(Color src, ColorHSV &dest); -void HSV2RGB(ColorHSV src, Color &dest); - -}; // namespace Gfx - diff --git a/src/graphics/common/device.cpp b/src/graphics/common/device.cpp deleted file mode 100644 index 53274b3..0000000 --- a/src/graphics/common/device.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "graphics/common/device.h" - -//! Sets the default values -Gfx::DeviceConfig::DeviceConfig() -{ - width = 800; - height = 600; - bpp = 16; - fullScreen = false; - resizeable = false; - hardwareAccel = true; - doubleBuf = true; - noFrame = false; -}
\ No newline at end of file diff --git a/src/graphics/common/device.h b/src/graphics/common/device.h deleted file mode 100644 index 5900570..0000000 --- a/src/graphics/common/device.h +++ /dev/null @@ -1,52 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * 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/. - -// device.h - -#pragma once - - -namespace Gfx { - -struct DeviceConfig -{ - //! Screen width - int width; - //! Screen height - int height; - //! Bits per pixel - int bpp; - //! Full screen - bool fullScreen; - //! Resizeable window - bool resizeable; - //! Hardware acceleration - bool hardwareAccel; - //! Double buffering - bool doubleBuf; - //! No window frame (also set with full screen) - bool noFrame; - - DeviceConfig(); -}; - -class CDevice -{ - // TODO -}; - -}; // namespace Gfx diff --git a/src/graphics/common/engine.cpp b/src/graphics/common/engine.cpp deleted file mode 100644 index 3b9a89d..0000000 --- a/src/graphics/common/engine.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * 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/. - -// engine.cpp - -#include "graphics/common/engine.h" - -#include <GL/gl.h> -#include <GL/glu.h> - - -// TODO implementation - -Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app) -{ - // TODO -} - -Gfx::CEngine::~CEngine() -{ - // TODO -} - -int Gfx::CEngine::Render() -{ - /* Just a hello world for now */ - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glShadeModel(GL_SMOOTH); - glDisable(GL_DEPTH_TEST); - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluOrtho2D(-10.0f, 10.0f, -10.0f, 10.0f); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - //glTranslatef(0.0f, 0.0f, -6.0f); - - glBegin(GL_TRIANGLES); - { - glColor3f(1.0f, 0.0f, 0.0f); - glVertex2f(-2.0f, -1.0f); - glColor3f(0.0f, 1.0f, 0.0f); - glVertex2f(2.0f, -1.0f); - glColor3f(0.0f, 0.0f, 1.0f); - glVertex2f(0.0f, 1.5f); - } - glEnd(); - - glFlush(); - - return 1; -} diff --git a/src/graphics/common/engine.h b/src/graphics/common/engine.h deleted file mode 100644 index 6d2937c..0000000 --- a/src/graphics/common/engine.h +++ /dev/null @@ -1,715 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * 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/. - -// engine.h - -#pragma once - - -#include "graphics/common/color.h" -#include "graphics/common/material.h" -#include "graphics/common/vertex.h" -#include "math/intpoint.h" -#include "math/matrix.h" -#include "math/point.h" -#include "math/vector.h" - - -class CApplication; -class CInstanceManager; -class CObject; -class CSound; - - -namespace Gfx { - -class CDevice; -class CLight; -class CText; -class CParticle; -class CWater; -class CCloud; -class CLightning; -class CPlanet; -class CTerrain; - - -//const int MAXOBJECT = 1200; -//const int MAXSHADOW = 500; -//const int MAXGROUNDSPOT = 100; - - -enum ObjectType -{ - //! Object doesn't exist - OBJTYPE_NULL = 0, - //! Terrain - OBJTYPE_TERRAIN = 1, - //! Fixed object - OBJTYPE_FIX = 2, - //! Moving object - OBJTYPE_VEHICULE = 3, - //! Part of a moving object - OBJTYPE_DESCENDANT = 4, - //! Fixed object type quartz - OBJTYPE_QUARTZ = 5, - //! Fixed object type metal - OBJTYPE_METAL = 6 -}; - -enum TriangleType -{ - //! triangles - TRIANGLE_TYPE_6T = 1, - //! surfaces - TRIANGLE_TYPE_6S = 2 -}; - -enum Mapping -{ - MAPPING_X = 1, - MAPPING_Y = 2, - MAPPING_Z = 3, - MAPPING_1X = 4, - MAPPING_1Y = 5, - MAPPING_1Z = 6 -}; - -enum MouseType -{ - MOUSE_HIDE = 0, // no mouse - MOUSE_NORM = 1, - MOUSE_WAIT = 2, - MOUSE_EDIT = 3, - MOUSE_HAND = 4, - MOUSE_CROSS = 5, - MOUSE_SHOW = 6, - MOUSE_NO = 7, - MOUSE_MOVE = 8, // + - MOUSE_MOVEH = 9, // - - MOUSE_MOVEV = 10, // | - MOUSE_MOVED = 11, // / - MOUSE_MOVEI = 12, // \ // - MOUSE_SCROLLL = 13, // << - MOUSE_SCROLLR = 14, // >> - MOUSE_SCROLLU = 15, // ^ - MOUSE_SCROLLD = 16, // v - MOUSE_TARGET = 17 -}; - -enum ShadowType -{ - SHADOW_NORM = 0, - SHADOW_WORM = 1 -}; - -enum RenderState -{ - //! Normal opaque materials - RSTATE_NORMAL = 0, - //! The transparent texture (black = no) - RSTATE_TTEXTURE_BLACK = (1<<0), - //! The transparent texture (white = no) - RSTATE_TTEXTURE_WHITE = (1<<1), - //! The transparent diffuse color - RSTATE_TDIFFUSE = (1<<2), - //! Texture wrap - RSTATE_WRAP = (1<<3), - //! Texture borders with solid color - RSTATE_CLAMP = (1<<4), - //! Light texture (ambient max) - RSTATE_LIGHT = (1<<5), - //! Double black texturing - RSTATE_DUAL_BLACK = (1<<6), - //! Double white texturing - RSTATE_DUAL_WHITE = (1<<7), - //! Part 1 (no change in. MOD!) - RSTATE_PART1 = (1<<8), - //! Part 2 - RSTATE_PART2 = (1<<9), - //! Part 3 - RSTATE_PART3 = (1<<10), - //! Part 4 - RSTATE_PART4 = (1<<11), - //! Double-sided face - RSTATE_2FACE = (1<<12), - //! Image using alpha channel - RSTATE_ALPHA = (1<<13), - //! Always use 2nd floor texturing - RSTATE_SECOND = (1<<14), - //! Causes the fog - RSTATE_FOG = (1<<15), - //! The transparent color (black = no) - RSTATE_TCOLOR_BLACK = (1<<16), - //! The transparent color (white = no) - RSTATE_TCOLOR_WHITE = (1<<17) -}; - - -struct Triangle -{ - Gfx::VertexTex2 triangle[3]; - Gfx::Material material; - int state; - char texName1[20]; - char texName2[20]; -}; - - -struct ObjLevel6 -{ - int totalPossible; - int totalUsed; - Gfx::Material material; - int state; - Gfx::TriangleType type; - Gfx::VertexTex2 vertex[1]; -}; - -struct ObjLevel5 -{ - int totalPossible; - int totalUsed; - int reserve; - Gfx::ObjLevel6* table[1]; -}; - -struct ObjLevel4 -{ - int totalPossible; - int totalUsed; - float min, max; - Gfx::ObjLevel5* table[1]; -}; - -struct ObjLevel3 -{ - int totalPossible; - int totalUsed; - int objRank; - Gfx::ObjLevel4* table[1]; -}; - -struct ObjLevel2 -{ - int totalPossible; - int totalUsed; - char texName1[20]; - char texName2[20]; - Gfx::ObjLevel3* table[1]; -}; - -struct ObjLevel1 -{ - int totalPossible; - int totalUsed; - Gfx::ObjLevel2* table[1]; -}; - - -struct Object -{ - bool used; // true -> object exists - bool visible; // true -> visible object - bool drawWorld; // true -> shape behind the interface - bool drawFront; // true -> shape before the interface - int totalTriangle; // number of triangles used - Gfx::ObjectType type; // type of the object (TYPE*) - Math::Matrix transform; // transformation matrix - float distance; // distance point of view - original - Math::Vector bboxMin; // bounding box of the object - Math::Vector bboxMax; // (the origin 0, 0, 0 is always included) - float radius; // radius of the sphere at the origin - int shadowRank; // rank of the associated shadow - float transparency; // transparency of the object (0 .. 1) -}; - -struct Shadow -{ - bool used; // true -> object exists - bool hide; // true -> invisible shadow (object carried by ex.) - int objRank; // rank of the object - Gfx::ShadowType type; // type of shadow - Math::Vector pos; // position for the shadow - Math::Vector normal; // normal terrain - float angle; // angle of the shadow - float radius; // radius of the shadow - float intensity; // intensity of the shadow - float height; // height from the ground -}; - -struct GroundSpot -{ - bool used; // true -> object exists - Gfx::Color color; // color of the shadow - float min, max; // altitudes min / max - float smooth; // transition area - Math::Vector pos; // position for the shadow - float radius; // radius of the shadow - Math::Vector drawPos; // drawn to position the shade - float drawRadius; // radius of the shadow drawn -}; - -struct GroundMark -{ - bool used; // true -> object exists - bool draw; // true -> drawn mark - int phase; // 1 = increase, 2 = fixed, 3 = decrease - float delay[3]; // time for 3 phases - float fix; // fixed time - Math::Vector pos; // position for marks - float radius; // radius of marks - float intensity; // color intensity - Math::Vector drawPos; // drawn in position marks - float drawRadius; // radius marks drawn - float drawIntensity; // current drawn - int dx, dy; // dimensions table - char* table; // pointer to the table -}; - - - -class CEngine -{ -public: - CEngine(CInstanceManager *iMan, CApplication *app); - ~CEngine(); - - void SetDevice(Gfx::CDevice *device); - Gfx::CDevice* RetDevice(); - - void SetTerrain(Gfx::CTerrain* terrain); - - bool WriteProfile(); - - void SetPause(bool pause); - bool RetPause(); - - void SetMovieLock(bool lock); - bool RetMovieLock(); - - void SetShowStat(bool show); - bool RetShowStat(); - - void SetRenderEnable(bool enable); - - int OneTimeSceneInit(); - int InitDeviceObjects(); - int DeleteDeviceObjects(); - int RestoreSurfaces(); - int Render(); - int FrameMove(float rTime); - void StepSimul(float rTime); - int FinalCleanup(); - void AddStatisticTriangle(int nb); - int RetStatisticTriangle(); - void SetHiliteRank(int *rankList); - bool GetHilite(Math::Point &p1, Math::Point &p2); - bool GetSpriteCoord(int &x, int &y); - void SetInfoText(int line, char* text); - char * RetInfoText(int line); - //LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - void FirstExecuteAdapt(bool first); - //int GetVidMemTotal(); - //bool IsVideo8MB(); - //bool IsVideo32MB(); - - bool EnumDevices(char *bufDevices, int lenDevices, char *bufModes, int lenModes, int &totalDevices, int &selectDevices, int &totalModes, int &selectModes); - bool RetFullScreen(); - bool ChangeDevice(char *device, char *mode, bool full); - - Math::Matrix* RetMatView(); - Math::Matrix* RetMatLeftView(); - Math::Matrix* RetMatRightView(); - - void TimeInit(); - void TimeEnterGel(); - void TimeExitGel(); - float TimeGet(); - - int RetRestCreate(); - int CreateObject(); - void FlushObject(); - bool DeleteObject(int objRank); - bool SetDrawWorld(int objRank, bool draw); - bool SetDrawFront(int objRank, bool draw); - bool AddTriangle(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max, bool globalUpdate); - bool AddSurface(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max, bool globalUpdate); - bool AddQuick(int objRank, Gfx::ObjLevel6* buffer, char* texName1, char* texName2, float min, float max, bool globalUpdate); - Gfx::ObjLevel6* SearchTriangle(int objRank, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max); - void ChangeLOD(); - bool ChangeSecondTexture(int objRank, char* texName2); - int RetTotalTriangles(int objRank); - int GetTriangles(int objRank, float min, float max, Gfx::Triangle* buffer, int size, float percent); - bool GetBBox(int objRank, Math::Vector &min, Math::Vector &max); - bool ChangeTextureMapping(int objRank, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max, Gfx::Mapping mode, float au, float bu, float av, float bv); - bool TrackTextureMapping(int objRank, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max, Gfx::Mapping mode, float pos, float factor, float tl, float ts, float tt); - bool SetObjectTransform(int objRank, const Math::Matrix &transform); - bool GetObjectTransform(int objRank, Math::Matrix &transform); - bool SetObjectType(int objRank, Gfx::ObjectType type); - Gfx::ObjectType RetObjectType(int objRank); - bool SetObjectTransparency(int objRank, float value); - - bool ShadowCreate(int objRank); - void ShadowDelete(int objRank); - bool SetObjectShadowHide(int objRank, bool hide); - bool SetObjectShadowType(int objRank, Gfx::ShadowType type); - bool SetObjectShadowPos(int objRank, const Math::Vector &pos); - bool SetObjectShadowNormal(int objRank, const Math::Vector &n); - bool SetObjectShadowAngle(int objRank, float angle); - bool SetObjectShadowRadius(int objRank, float radius); - bool SetObjectShadowIntensity(int objRank, float intensity); - bool SetObjectShadowHeight(int objRank, float h); - float RetObjectShadowRadius(int objRank); - - void GroundSpotFlush(); - int GroundSpotCreate(); - void GroundSpotDelete(int rank); - bool SetObjectGroundSpotPos(int rank, const Math::Vector &pos); - bool SetObjectGroundSpotRadius(int rank, float radius); - bool SetObjectGroundSpotColor(int rank, const Gfx::Color &color); - bool SetObjectGroundSpotMinMax(int rank, float min, float max); - bool SetObjectGroundSpotSmooth(int rank, float smooth); - - int GroundMarkCreate(Math::Vector pos, float radius, float delay1, float delay2, float delay3, int dx, int dy, char* table); - bool GroundMarkDelete(int rank); - - void Update(); - - void SetViewParams(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, const Math::Vector &vUpVec, float fEyeDistance); - - bool FreeTexture(char* name); - bool LoadTexture(char* name, int stage=0); - bool LoadAllTexture(); - - void SetLimitLOD(int rank, float limit); - float RetLimitLOD(int rank, bool last=false); - - void SetTerrainVision(float vision); - - void SetGroundSpot(bool mode); - bool RetGroundSpot(); - void SetShadow(bool mode); - bool RetShadow(); - void SetDirty(bool mode); - bool RetDirty(); - void SetFog(bool mode); - bool RetFog(); - bool RetStateColor(); - - void SetSecondTexture(int texNum); - int RetSecondTexture(); - - void SetRankView(int rank); - int RetRankView(); - - void SetDrawWorld(bool draw); - void SetDrawFront(bool draw); - - void SetAmbiantColor(const Gfx::Color &color, int rank=0); - Gfx::Color RetAmbiantColor(int rank=0); - - void SetWaterAddColor(const Gfx::Color &color); - Gfx::Color RetWaterAddColor(); - - void SetFogColor(const Gfx::Color &color, int rank=0); - Gfx::Color RetFogColor(int rank=0); - - void SetDeepView(float length, int rank=0, bool ref=false); - float RetDeepView(int rank=0); - - void SetFogStart(float start, int rank=0); - float RetFogStart(int rank=0); - - void SetBackground(char *name, Gfx::Color up=Gfx::Color(), Gfx::Color down=Gfx::Color(), Gfx::Color cloudUp=Gfx::Color(), Gfx::Color cloudDown=Gfx::Color(), bool full=false, bool quarter=false); - void RetBackground(char *name, Gfx::Color &up, Gfx::Color &down, Gfx::Color &cloudUp, Gfx::Color &cloudDown, bool &full, bool &quarter); - void SetFrontsizeName(char *name); - void SetOverFront(bool front); - void SetOverColor(const Gfx::Color &color=Gfx::Color(), int mode=RSTATE_TCOLOR_BLACK); - - void SetParticuleDensity(float value); - float RetParticuleDensity(); - float ParticuleAdapt(float factor); - - void SetClippingDistance(float value); - float RetClippingDistance(); - - void SetObjectDetail(float value); - float RetObjectDetail(); - - void SetGadgetQuantity(float value); - float RetGadgetQuantity(); - - void SetTextureQuality(int value); - int RetTextureQuality(); - - void SetTotoMode(bool present); - bool RetTotoMode(); - - void SetLensMode(bool present); - bool RetLensMode(); - - void SetWaterMode(bool present); - bool RetWaterMode(); - - void SetBlitzMode(bool present); - bool RetBlitzMode(); - - void SetSkyMode(bool present); - bool RetSkyMode(); - - void SetBackForce(bool present); - bool RetBackForce(); - - void SetPlanetMode(bool present); - bool RetPlanetMode(); - - void SetLightMode(bool present); - bool RetLightMode(); - - void SetEditIndentMode(bool auto); - bool RetEditIndentMode(); - - void SetEditIndentValue(int value); - int RetEditIndentValue(); - - void SetSpeed(float speed); - float RetSpeed(); - - void SetTracePrecision(float factor); - float RetTracePrecision(); - - void SetFocus(float focus); - float RetFocus(); - Math::Vector RetEyePt(); - Math::Vector RetLookatPt(); - float RetEyeDirH(); - float RetEyeDirV(); - Math::Point RetDim(); - void UpdateMatProj(); - - void ApplyChange(); - - void FlushPressKey(); - void ResetKey(); - void SetKey(int keyRank, int option, int key); - int RetKey(int keyRank, int option); - - void SetJoystick(bool enable); - bool RetJoystick(); - - void SetDebugMode(bool mode); - bool RetDebugMode(); - bool RetSetupMode(); - - bool IsVisiblePoint(const Math::Vector &pos); - - int DetectObject(Math::Point mouse); - void SetState(int state, Gfx::Color color=Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)); - void SetTexture(char *name, int stage=0); - void SetMaterial(const Gfx::Material &mat); - - void MoveMousePos(Math::Point pos); - void SetMousePos(Math::Point pos); - Math::Point RetMousePos(); - void SetMouseType(Gfx::MouseType type); - Gfx::MouseType RetMouseType(); - void SetMouseHide(bool hide); - bool RetMouseHide(); - void SetNiceMouse(bool nice); - bool RetNiceMouse(); - bool RetNiceMouseCap(); - - CText* RetText(); - - bool ChangeColor(char *name, Gfx::Color colorRef1, Gfx::Color colorNew1, Gfx::Color colorRef2, Gfx::Color colorNew2, float tolerance1, float tolerance2, Math::Point ts, Math::Point ti, Math::Point *pExclu=0, float shift=0.0f, bool hSV=false); - bool OpenImage(char *name); - bool CopyImage(); - bool LoadImage(); - bool ScrollImage(int dx, int dy); - bool SetDot(int x, int y, Gfx::Color color); - bool CloseImage(); - bool WriteScreenShot(char *filename, int width, int height); - //bool GetRenderDC(HDC &hDC); - //bool ReleaseRenderDC(HDC &hDC); - //PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp); - //bool CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC); - -protected: - void MemSpace1(Gfx::ObjLevel1 *&p, int nb); - void MemSpace2(Gfx::ObjLevel2 *&p, int nb); - void MemSpace3(Gfx::ObjLevel3 *&p, int nb); - void MemSpace4(Gfx::ObjLevel4 *&p, int nb); - void MemSpace5(Gfx::ObjLevel5 *&p, int nb); - void MemSpace6(Gfx::ObjLevel6 *&p, int nb); - - Gfx::ObjLevel2* AddLevel1(Gfx::ObjLevel1 *&p1, char* texName1, char* texName2); - Gfx::ObjLevel3* AddLevel2(Gfx::ObjLevel2 *&p2, int objRank); - Gfx::ObjLevel4* AddLevel3(Gfx::ObjLevel3 *&p3, float min, float max); - Gfx::ObjLevel5* AddLevel4(Gfx::ObjLevel4 *&p4, int reserve); - Gfx::ObjLevel6* AddLevel5(Gfx::ObjLevel5 *&p5, Gfx::TriangleType type, const Gfx::Material &mat, int state, int nb); - - bool IsVisible(int objRank); - bool DetectBBox(int objRank, Math::Point mouse); - bool DetectTriangle(Math::Point mouse, Gfx::VertexTex2 *triangle, int objRank, float &dist); - bool TransformPoint(Math::Vector &p2D, int objRank, Math::Vector p3D); - void ComputeDistance(); - void UpdateGeometry(); - void RenderGroundSpot(); - void DrawShadow(); - void DrawBackground(); - void DrawBackgroundGradient(Gfx::Color up, Gfx::Color down); - void DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, char *name); - void DrawBackgroundImage(); - void DrawPlanet(); - void DrawFrontsize(); - void DrawOverColor(); - bool GetBBox2D(int objRank, Math::Point &min, Math::Point &max); - void DrawHilite(); - void DrawMouse(); - void DrawSprite(Math::Point pos, Math::Point dim, int icon); - -protected: - CInstanceManager* m_iMan; - CApplication* m_app; - Gfx::CDevice* m_device; - Gfx::CText* m_text; - Gfx::CLight* m_light; - Gfx::CParticle* m_particule; - Gfx::CWater* m_water; - Gfx::CCloud* m_cloud; - Gfx::CLightning* m_blitz; - Gfx::CPlanet* m_planet; - Gfx::CTerrain* m_terrain; - CSound* m_sound; - - int m_blackSrcBlend[2]; - int m_blackDestBlend[2]; - int m_whiteSrcBlend[2]; - int m_whiteDestBlend[2]; - int m_diffuseSrcBlend[2]; - int m_diffuseDestBlend[2]; - int m_alphaSrcBlend[2]; - int m_alphaDestBlend[2]; - - Math::Matrix m_matProj; - Math::Matrix m_matLeftView; - Math::Matrix m_matRightView; - Math::Matrix m_matView; - float m_focus; - - Math::Matrix m_matWorldInterface; - Math::Matrix m_matProjInterface; - Math::Matrix m_matViewInterface; - - long m_baseTime; - long m_stopTime; - float m_absTime; - float m_lastTime; - float m_speed; - bool m_pause; - bool m_render; - bool m_movieLock; - - Math::IntPoint m_dim; - Math::IntPoint m_lastDim; - Gfx::ObjLevel1* m_objectPointer; - int m_objectParamTotal; - Gfx::Object* m_objectParam; - int m_shadowTotal; - Gfx::Shadow* m_shadow; - Gfx::GroundSpot* m_groundSpot; - Gfx::GroundMark m_groundMark; - Math::Vector m_eyePt; - Math::Vector m_lookatPt; - float m_eyeDirH; - float m_eyeDirV; - int m_rankView; - Gfx::Color m_ambiantColor[2]; - Gfx::Color m_backColor[2]; - Gfx::Color m_fogColor[2]; - float m_deepView[2]; - float m_fogStart[2]; - Gfx::Color m_waterAddColor; - int m_statisticTriangle; - bool m_updateGeometry; - char m_infoText[10][200]; - int m_alphaMode; - bool m_stateColor; - bool m_forceStateColor; - bool m_groundSpotVisible; - bool m_shadowVisible; - bool m_dirty; - bool m_fog; - bool m_firstGroundSpot; - int m_secondTexNum; - char m_backgroundName[50]; - Gfx::Color m_backgroundColorUp; - Gfx::Color m_backgroundColorDown; - Gfx::Color m_backgroundCloudUp; - Gfx::Color m_backgroundCloudDown; - bool m_backgroundFull; - bool m_backgroundQuarter; - bool m_overFront; - Gfx::Color m_overColor; - int m_overMode; - char m_frontsizeName[50]; - bool m_drawWorld; - bool m_drawFront; - float m_limitLOD[2]; - float m_particuleDensity; - float m_clippingDistance; - float m_lastClippingDistance; - float m_objectDetail; - float m_lastObjectDetail; - float m_terrainVision; - float m_gadgetQuantity; - int m_textureQuality; - bool m_totoMode; - bool m_lensMode; - bool m_waterMode; - bool m_skyMode; - bool m_backForce; - bool m_planetMode; - bool m_lightMode; - bool m_editIndentMode; - int m_editIndentValue; - float m_tracePrecision; - - int m_hiliteRank[100]; - bool m_hilite; - Math::Point m_hiliteP1; - Math::Point m_hiliteP2; - - int m_lastState; - Gfx::Color m_lastColor; - char m_lastTexture[2][50]; - Gfx::Material m_lastMaterial; - - Math::Point m_mousePos; - Gfx::MouseType m_mouseType; - bool m_mouseHide; - bool m_niceMouse; - - //LPDIRECTDRAWSURFACE7 m_imageSurface; - //DDSURFACEDESC2 m_imageDDSD; - //WORD* m_imageCopy; - //int m_imageDX; - //int m_imageDY; -}; - -}; // namespace Gfx diff --git a/src/graphics/common/light.cpp b/src/graphics/common/light.cpp deleted file mode 100644 index d938256..0000000 --- a/src/graphics/common/light.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * 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/. - -// light.cpp - -#include "graphics/common/light.h" - -// TODO implementation
\ No newline at end of file diff --git a/src/graphics/common/light.h b/src/graphics/common/light.h deleted file mode 100644 index dec9912..0000000 --- a/src/graphics/common/light.h +++ /dev/null @@ -1,115 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * 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/. - -// light.h - -#pragma once - - -#include "graphics/common/color.h" -#include "math/vector.h" - - -namespace Gfx { - -/** \enum LightType - * \brief Type of light */ -enum LightType -{ - LT_Point, - LT_Spot, - LT_Directional -}; - -/** - * \struct Light - * \brief Light - * - * This structure was created as analog to DirectX's D3DLIGHT. - * - * It contains analogous fields as the D3DLIGHT struct. - */ -struct Light -{ - //! Type of light source - Gfx::LightType type; - //! Color of light - Gfx::Color color; - //! Position in world space - Math::Vector position; - //! Direction in world space - Math::Vector direction; - //! Cutoff range - float range; - //! Falloff - float falloff; - //! Constant attenuation - float attenuation0; - //! Linear attenuation - float attenuation1; - //! Quadratic attenuation - float attenuation2; - //! Inner angle of spotlight cone - float theta; - //! Outer angle of spotlight cone - float phi; - - Light() : type(LT_Point), range(0.0f), falloff(0.0f), - attenuation0(0.0f), attenuation1(0.0f), attenuation2(0.0f), - theta(0.0f), phi(0.0f) {} -}; - -struct LightProg -{ - float starting; - float ending; - float current; - float progress; - float speed; -}; - -/** - * \struct SceneLight - * \brief Dynamic light in 3D scene - * - * TODO documentation - */ -struct SceneLight -{ - //! true -> light exists - bool used; - //! true -> light turned on - bool enable; - - //! Type of all objects included - //D3DTypeObj incluType; - //! Type of all objects excluded - //D3DTypeObj excluType; - - //! Configuration of the light - Gfx::Light light; - - //! intensity (0 .. 1) - Gfx::LightProg intensity; - Gfx::LightProg colorRed; - Gfx::LightProg colorGreen; - Gfx::LightProg colorBlue; -}; - -// TODO CLight - -}; // namespace Gfx diff --git a/src/graphics/common/model.cpp b/src/graphics/common/model.cpp deleted file mode 100644 index c415fb8..0000000 --- a/src/graphics/common/model.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * 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/. - -// model.cpp - -#include "graphics/common/model.h" - - -// TODO implementation diff --git a/src/graphics/common/model.h b/src/graphics/common/model.h deleted file mode 100644 index e8a5f19..0000000 --- a/src/graphics/common/model.h +++ /dev/null @@ -1,141 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * 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/. - -// model.h - -#pragma once - -#include "engine.h" -#include "common/event.h" -#include "modfile.h" -#include "vertex.h" -#include "math/point.h" - - -class CInstanceManager; -class CModFile; -class CInterface; - - -namespace Gfx { - -class CEngine; - - -class CModel { - public: - CModel(CInstanceManager* iMan); - ~CModel(); - - void StartUserAction(); - void StopUserAction(); - - bool EventProcess(const Event &event); - - void InitView(); - void InitViewFromSelect(); - void UpdateView(); - void ViewMove(const Event &event, float speed); - - protected: - bool EventFrame(const Event &event); - bool GetVertex(int rank, Gfx::VertexTex2 &vertex); - bool SetVertex(int rank, Gfx::VertexTex2 &vertex); - Math::Vector RetSelectCDG(); - Math::Vector RetSelectNormal(); - void SmoothSelect(); - void PlaneSelect(); - void ColorSelect(); - void StateSelect(); - void MoveSelect(Math::Vector move); - void OperSelect(Math::Vector move, char oper); - void ReadScript(char *filename); - void BBoxCompute(Math::Vector &min, Math::Vector &max); - bool IsMappingSelectPlausible(Gfx::Mapping D3Dmode); - void MappingSelect(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); - void MappingSelectSpherical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); - Math::Vector RetMappingCenter(Math::Vector pos, Math::Vector min); - void MappingSelectCylindrical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); - void MappingSelectFace(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); - void MappingSelect2(int texNum2, int subdiv, int offsetU, int offsetV, bool bMirrorX, bool bMirrorY); - void MappingSelectPlane2(int mode, bool bMirrorX, bool bMirrorY); - void MappingSelectSpherical2(bool bMirrorX, bool bMirrorY); - void MappingSelectMagic2(bool bMirrorX, bool bMirrorY); - int SearchNext(int rank, int step); - int SearchSamePlane(int first, int step); - void CurrentSearchNext(int step, bool bControl); - void CurrentInit(); - void CurrentSelect(bool bSelect); - void DeselectAll(); - void SelectAll(); - void SelectZone(int first, int last); - void SelectTerm(); - void DefaultSelect(); - void SelectDelete(); - void Compress(); - void MinMaxSelect(); - void MinMaxChange(); - void UpdateInfoText(); - int* RetTextureTable(); - void TexturePartUpdate(); - void TextureRankChange(int step); - void TexturePartChange(int step); - void PutTextureValues(); - void GetTextureValues(); - void GetModelName(char *buffer); - void GetDXFName(char *buffer); - void GetScriptName(char *buffer); - bool IsEditFocus(); - - protected: - CInstanceManager* m_iMan; - Gfx::CEngine* m_engine; - CModFile* m_modFile; - CInterface* m_interface; - - float m_time; - ModelTriangle* m_triangleTable; - int m_triangleSel1; - int m_triangleSel2; - int m_mode; - int m_textureMode; - int m_textureRotate; - bool m_bTextureMirrorX; - bool m_bTextureMirrorY; - Math::Point m_textureInf; - Math::Point m_textureSup; - int m_texturePart; - int m_textureRank; - char m_textureName[20]; - bool m_bDisplayTransparent; - bool m_bDisplayOnlySelection; - float m_viewHeight; - float m_viewDist; - float m_viewAngleH; - float m_viewAngleV; - int m_color; - int m_state; - int m_secondTexNum; - int m_secondSubdiv; - int m_secondOffsetU; - int m_secondOffsetV; - char m_oper; - float m_min; - float m_max; -}; - -}; // namespace Gfx diff --git a/src/graphics/common/modfile.cpp b/src/graphics/common/modfile.cpp deleted file mode 100644 index 6f80be7..0000000 --- a/src/graphics/common/modfile.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * 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/. - -// modfile.cpp - -#include "graphics/common/modfile.h" - - -// TODO implementation
\ No newline at end of file diff --git a/src/graphics/common/modfile.h b/src/graphics/common/modfile.h deleted file mode 100644 index c81739b..0000000 --- a/src/graphics/common/modfile.h +++ /dev/null @@ -1,114 +0,0 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * 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/. - -// modfile.h - -#include "engine.h" -#include "vertex.h" -#include "material.h" -#include "math/vector.h" - - -class CInstanceManager; - - -namespace Gfx { - -struct OldModelTriangle1 -{ - char bUsed; // TRUE -> using - char bSelect; // TRUE -> selected - Vertex p1; - Vertex p2; - Vertex p3; - Material material; - char texName[20]; - float min; - float max; -}; // length = 196 bytes - -struct OldModelTriangle2 -{ - char bUsed; // TRUE -> used - char bSelect; // TRUE -> selected - Vertex p1; - Vertex p2; - Vertex p3; - Material material; - char texName[20]; - float min; - float max; - long state; - short reserve1; - short reserve2; - short reserve3; - short reserve4; -}; - -struct ModelTriangle -{ - char bUsed; // TRUE -> used - char bSelect; // TRUE -> selected - VertexTex2 p1; - VertexTex2 p2; - VertexTex2 p3; - Material material; - char texName[20]; - float min; - float max; - long state; - short texNum2; - short reserve2; - short reserve3; - short reserve4; -}; // length = 208 bytes - - - - -class CModFile { -public: - CModFile(CInstanceManager* iMan); - ~CModFile(); - - bool ReadDXF(char *filename, float min, float max); - bool AddModel(char *filename, int first, bool bEdit=false, bool bMeta=true); - bool ReadModel(char *filename, bool bEdit=false, bool bMeta=true); - bool WriteModel(char *filename); - - bool CreateEngineObject(int objRank, int addState=0); - void Mirror(); - - void SetTriangleUsed(int total); - int RetTriangleUsed(); - int RetTriangleMax(); - ModelTriangle* RetTriangleList(); - - float RetHeight(Math::Vector pos); - -protected: - bool CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max); - -protected: - CInstanceManager* m_iMan; - CEngine* m_engine; - - ModelTriangle* m_triangleTable; - int m_triangleUsed; -}; - -}; diff --git a/src/graphics/common/vertex.h b/src/graphics/common/vertex.h deleted file mode 100644 index 0cc6402..0000000 --- a/src/graphics/common/vertex.h +++ /dev/null @@ -1,68 +0,0 @@ -// * 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/. - -// vertex.h - -#pragma once - - -#include "math/vector.h" -#include "math/point.h" - -namespace Gfx { - -/** - * \struct Vertex - * \brief Vertex of a primitive - * - * This structure was created as analog to DirectX's D3DVERTEX. - * - * It contains: - * - vertex coordinates (x,y,z) as Math::Vector, - * - normal coordinates (nx,ny,nz) as Math::Vector - * - texture coordinates (u,v) as Math::Point. - */ -struct Vertex -{ - Math::Vector coord; - Math::Vector normal; - Math::Point texCoord; - - Vertex(Math::Vector aCoord = Math::Vector(), - Math::Vector aNormal = Math::Vector(), - Math::Point aTexCoord = Math::Point()) - : coord(aCoord), normal(aNormal), texCoord(aTexCoord) {} -}; - -/** - * \struct VertexTex2 - * \brief Vertex with secondary texture coordinates - * - * In addition to fields from Gfx::Vector, it contains - * secondary texture coordinates (u2, v2) as Math::Point - */ -struct VertexTex2 : public Gfx::Vertex -{ - Math::Point texCoord2; - - VertexTex2(Math::Vector aCoord = Math::Vector(), - Math::Vector aNormal = Math::Vector(), - Math::Point aTexCoord = Math::Point(), - Math::Point aTexCoord2 = Math::Point()) - : Vertex(aCoord, aNormal, aTexCoord), texCoord2(aTexCoord2) {} -}; - -}; // namespace Gfx diff --git a/src/graphics/core/README.txt b/src/graphics/core/README.txt new file mode 100644 index 0000000..12beef9 --- /dev/null +++ b/src/graphics/core/README.txt @@ -0,0 +1,6 @@ +src/graphics/core + +Abstract core of graphics engine + +Core types, enums, structs and CDevice abstract class that define +the abstract graphics device used in graphics engine diff --git a/src/graphics/core/color.cpp b/src/graphics/core/color.cpp new file mode 100644 index 0000000..f241227 --- /dev/null +++ b/src/graphics/core/color.cpp @@ -0,0 +1,103 @@ +// * 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/. + +// color.cpp + +#include "graphics/core/color.h" + +#include "math/func.h" + + +Gfx::ColorHSV Gfx::RGB2HSV(Gfx::Color color) +{ + Gfx::ColorHSV result; + + float min = Math::Min(color.r, color.g, color.b); + float max = Math::Max(color.r, color.g, color.b); + + result.v = max; // intensity + + if ( max == 0.0f ) + { + result.s = 0.0f; // saturation + result.h = 0.0f; // undefined color! + } + else + { + float delta = max-min; + result.s = delta/max; // saturation + + if ( color.r == max ) // between yellow & magenta + { + result.h = (color.g-color.b)/delta; + } + else if ( color.g == max ) // between cyan & yellow + { + result.h = 2.0f+(color.b-color.r)/delta; + } + else // between magenta & cyan + { + result.h = 4.0f+(color.r-color.g)/delta; + } + + result.h *= 60.0f; // in degrees + if ( result.h < 0.0f ) result.h += 360.0f; + result.h /= 360.0f; // 0..1 + } + + return result; +} + +Gfx::Color Gfx::HSV2RGB(Gfx::ColorHSV color) +{ + Gfx::Color result; + + color.h = Math::Norm(color.h)*360.0f; + color.s = Math::Norm(color.s); + color.v = Math::Norm(color.v); + + if ( color.s == 0.0f ) // zero saturation? + { + result.r = color.v; + result.g = color.v; + result.b = color.v; // gray + } + else + { + if ( color.h == 360.0f ) color.h = 0.0f; + color.h /= 60.0f; + int i = static_cast<int>(color.h); // integer part (0 .. 5) + float f = color.h-i; // fractional part + + float v = color.v; + float p = color.v*(1.0f-color.s); + float q = color.v*(1.0f-(color.s*f)); + float t = color.v*(1.0f-(color.s*(1.0f-f))); + + switch (i) + { + case 0: result.r=v; result.g=t; result.b=p; break; + case 1: result.r=q; result.g=v; result.b=p; break; + case 2: result.r=p; result.g=v; result.b=t; break; + case 3: result.r=p; result.g=q; result.b=v; break; + case 4: result.r=t; result.g=p; result.b=v; break; + case 5: result.r=v; result.g=p; result.b=q; break; + } + } + + return result; +} + diff --git a/src/graphics/core/color.h b/src/graphics/core/color.h new file mode 100644 index 0000000..6973644 --- /dev/null +++ b/src/graphics/core/color.h @@ -0,0 +1,98 @@ +// * 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/. + +// color.h + +#pragma once + + +#include <sstream> + + +namespace Gfx { + +/** + \struct Color + \brief RGBA color */ +struct Color +{ + //! Red, green, blue and alpha components + float r, g, b, a; + + //! Constructor; default values are (0,0,0,0) = black + Color(float aR = 0.0f, float aG = 0.0f, float aB = 0.0f, float aA = 0.0f) + : r(aR), g(aG), b(aB), a(aA) {} + + inline Gfx::Color Inverse() const + { + return Gfx::Color(1.0f - r, 1.0f - g, 1.0f - b, 1.0f - a); + } + + //! Returns the struct cast to \c float* array; use with care! + inline float* Array() + { + return reinterpret_cast<float*>(this); + } + + //! Returns the struct cast to <tt>const float*</tt> array; use with care! + inline const float* Array() const + { + return reinterpret_cast<const float*>(this); + } + + //! Returns a string (r, g, b, a) + inline std::string ToString() const + { + std::stringstream s; + s.precision(3); + s << "(" << r << ", " << g << ", " << b << ", " << a << ")"; + return s.str(); + } + + inline bool operator==(const Gfx::Color &other) const + { + return r == other.r && g == other.g && b == other.b && a == other.a; + } +}; + +/** + \struct ColorHSV + \brief HSV color */ +struct ColorHSV +{ + float h, s, v; + + ColorHSV(float aH = 0.0f, float aS = 0.0f, float aV = 0.0f) + : h(aH), s(aS), v(aV) {} + + //! Returns a string "(h, s, v)" + inline std::string ToString() const + { + std::stringstream s; + s.precision(3); + s << "(" << h << ", " << s << ", " << v << ")"; + return s.str(); + } +}; + +//! Converts a RGB color to HSV color +Gfx::ColorHSV RGB2HSV(Gfx::Color color); + +//! Converts a HSV color to RGB color +Gfx::Color HSV2RGB(Gfx::ColorHSV color); + +}; // namespace Gfx + diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h new file mode 100644 index 0000000..c10b853 --- /dev/null +++ b/src/graphics/core/device.h @@ -0,0 +1,412 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * 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/. + +// device.h + +#pragma once + + +#include "graphics/core/color.h" +#include "graphics/core/light.h" +#include "graphics/core/material.h" +#include "graphics/core/texture.h" +#include "graphics/core/vertex.h" +#include "math/intsize.h" +#include "math/matrix.h" + +#include <string> + + +class CImage; + + +namespace Gfx { + +/** + \struct DeviceConfig + \brief General config for graphics device + + These settings are common window options set by SDL. +*/ +struct DeviceConfig +{ + //! Screen size + Math::IntSize size; + //! Bits per pixel + int bpp; + //! Full screen + bool fullScreen; + //! Resizeable window + bool resizeable; + //! Double buffering + bool doubleBuf; + //! No window frame (also set with full screen) + bool noFrame; + + //! Constructor calls LoadDefault() + DeviceConfig() { LoadDefault(); } + + //! Loads the default values + inline void LoadDefault() + { + size = Math::IntSize(800, 600); + bpp = 32; + fullScreen = false; + resizeable = false; + doubleBuf = true; + noFrame = false; + } +}; + + +/** + \enum TransformType + \brief Type of transformation in rendering pipeline + + These correspond to DirectX's three transformation matrices. */ +enum TransformType +{ + TRANSFORM_WORLD, + TRANSFORM_VIEW, + TRANSFORM_PROJECTION +}; + +/** + \enum RenderState + \brief Render states that can be enabled/disabled */ +enum RenderState +{ + RENDER_STATE_LIGHTING, + RENDER_STATE_TEXTURING, + RENDER_STATE_BLENDING, + RENDER_STATE_FOG, + RENDER_STATE_DEPTH_TEST, + RENDER_STATE_DEPTH_WRITE, + RENDER_STATE_ALPHA_TEST, + RENDER_STATE_CULLING, + RENDER_STATE_DITHERING +}; + +/** + \enum CompFunc + \brief Type of function used to compare values */ +enum CompFunc +{ + COMP_FUNC_NEVER, + COMP_FUNC_LESS, + COMP_FUNC_EQUAL, + COMP_FUNC_NOTEQUAL, + COMP_FUNC_LEQUAL, + COMP_FUNC_GREATER, + COMP_FUNC_GEQUAL, + COMP_FUNC_ALWAYS +}; + +/** + \enum BlendFunc + \brief Type of blending function */ +enum BlendFunc +{ + BLEND_ZERO, + BLEND_ONE, + BLEND_SRC_COLOR, + BLEND_INV_SRC_COLOR, + BLEND_DST_COLOR, + BLEND_INV_DST_COLOR, + BLEND_SRC_ALPHA, + BLEND_INV_SRC_ALPHA, + BLEND_DST_ALPHA, + BLEND_INV_DST_ALPHA, + BLEND_SRC_ALPHA_SATURATE +}; + +/** + \enum FogMode + \brief Type of fog calculation function */ +enum FogMode +{ + FOG_LINEAR, + FOG_EXP, + FOG_EXP2 +}; + +/** + \enum CullMode + \brief Culling mode for polygons */ +enum CullMode +{ + //! Cull clockwise side + CULL_CW, + //! Cull counter-clockwise side + CULL_CCW +}; + +/** + \enum ShadeModel + \brief Shade model used in rendering */ +enum ShadeModel +{ + SHADE_FLAT, + SHADE_SMOOTH +}; + +/** + \enum FillMode + \brief Polygon fill mode */ +enum FillMode +{ + //! Draw only points + FILL_POINT, + //! Draw only lines + FILL_LINES, + //! Draw full polygons + FILL_FILL +}; + +/** + \enum PrimitiveType + \brief Type of primitive to render */ +enum PrimitiveType +{ + PRIMITIVE_POINTS, + PRIMITIVE_LINES, + PRIMITIVE_LINE_STRIP, + PRIMITIVE_TRIANGLES, + PRIMITIVE_TRIANGLE_STRIP +}; + +/** + \enum IntersectPlane + \brief Intersection plane of projection volume + + These flags can be OR'd together. */ +enum IntersectPlane +{ + INTERSECT_PLANE_LEFT = 0x01, + INTERSECT_PLANE_RIGHT = 0x02, + INTERSECT_PLANE_TOP = 0x04, + INTERSECT_PLANE_BOTTOM = 0x08, + INTERSECT_PLANE_FRONT = 0x10, + INTERSECT_PLANE_BACK = 0x20, + INTERSECT_PLANE_ALL = INTERSECT_PLANE_LEFT | INTERSECT_PLANE_RIGHT | + INTERSECT_PLANE_TOP | INTERSECT_PLANE_BOTTOM | + INTERSECT_PLANE_FRONT | INTERSECT_PLANE_BACK +}; + +/* + +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() or CreateTexture() for some params + +Params from enum in struct TextureCreateParams or 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 + + It is based on DIRECT3DDEVICE class from DirectX to make it easier to port existing code. + It encapsulates the general graphics device state and provides a common interface + to graphics-specific functions which will be used throughout the program, + both in CEngine class and in UI classes. Note that it doesn't contain all functions from DirectX, + only those that were used in old code. + + */ +class CDevice +{ +public: + virtual ~CDevice() {} + + //! Initializes the device, setting the initial state + virtual bool Create() = 0; + //! Destroys the device, releasing every acquired resource + virtual void Destroy() = 0; + + //! Returns whether the device has been initialized + virtual bool GetWasInit() = 0; + //! Returns the last encountered error + virtual std::string GetError() = 0; + + //! Begins drawing the 3D scene + virtual void BeginScene() = 0; + //! Ends drawing the 3D scene + virtual void EndScene() = 0; + + //! Clears the screen to blank + virtual void Clear() = 0; + + //! Sets the transform matrix of given type + virtual void SetTransform(TransformType type, const Math::Matrix &matrix) = 0; + //! Returns the current transform matrix of given type + virtual const Math::Matrix& GetTransform(TransformType type) = 0; + //! Multiplies the current transform matrix of given type by given matrix + virtual void MultiplyTransform(TransformType type, const Math::Matrix &matrix) = 0; + + //! Sets the current material + virtual void SetMaterial(const Gfx::Material &material) = 0; + //! Returns the current material + virtual const Gfx::Material& GetMaterial() = 0; + + //! Returns the maximum number of lights available + virtual int GetMaxLightCount() = 0; + //! Sets the light at given index + virtual void SetLight(int index, const Gfx::Light &light) = 0; + //! Returns the current light at given index + virtual const Gfx::Light& GetLight(int index) = 0; + //! Enables/disables the light at given index + virtual void SetLightEnabled(int index, bool enabled) = 0; + //! Returns the current enable state of light at given index + virtual bool GetLightEnabled(int index) = 0; + + //! Creates a texture from image; the image can be safely removed after that + virtual Gfx::Texture CreateTexture(CImage *image, const Gfx::TextureCreateParams ¶ms) = 0; + //! Deletes a given texture, freeing it from video memory + virtual void DestroyTexture(const Gfx::Texture &texture) = 0; + //! Deletes all textures created so far + virtual void DestroyAllTextures() = 0; + + //! Returns the maximum number of multitexture stages + virtual int GetMaxTextureCount() = 0; + //! Sets the (multi)texture at given index + virtual void SetTexture(int index, const 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; + + //! Sets the params for texture stage with given index + virtual void SetTextureStageParams(int index, const Gfx::TextureStageParams ¶ms) = 0; + //! Returns the current params of texture stage with given index + virtual Gfx::TextureStageParams GetTextureStageParams(int index) = 0; + + //! Sets the texture factor to the given color value + virtual void SetTextureFactor(const 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, const Gfx::Vertex *vertices , int vertexCount) = 0; + //! Renders primitive composed of vertices with color information and single texture + virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexCol *vertices , int vertexCount) = 0; + //! Renders primitive composed of vertices with multitexturing (2 textures) + virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexTex2 *vertices, int vertexCount) = 0; + + //! Tests whether a sphere intersects the 6 clipping planes of projection volume + virtual int ComputeSphereVisibility(const Math::Vector ¢er, float radius) = 0; + + //! Enables/disables the given render state + virtual void SetRenderState(Gfx::RenderState state, bool enabled) = 0; + //! Returns the current setting of given render state + virtual bool GetRenderState(Gfx::RenderState state) = 0; + + //! Sets the function of depth test + virtual void SetDepthTestFunc(Gfx::CompFunc func) = 0; + //! Returns the current function of depth test + virtual Gfx::CompFunc GetDepthTestFunc() = 0; + + //! Sets the depth bias (constant value added to Z-coords) + virtual void SetDepthBias(float factor) = 0; + //! Returns the current depth bias + virtual float GetDepthBias() = 0; + + //! Sets the alpha test function and reference value + virtual void SetAlphaTestFunc(Gfx::CompFunc func, float refValue) = 0; + //! Returns the current alpha test function and reference value + virtual void GetAlphaTestFunc(Gfx::CompFunc &func, float &refValue) = 0; + + //! Sets the blending functions for source and destination operations + virtual void SetBlendFunc(Gfx::BlendFunc srcBlend, Gfx::BlendFunc dstBlend) = 0; + //! Returns the current blending functions for source and destination operations + virtual void GetBlendFunc(Gfx::BlendFunc &srcBlend, Gfx::BlendFunc &dstBlend) = 0; + + //! Sets the clear color + virtual void SetClearColor(const Gfx::Color &color) = 0; + //! Returns the current clear color + virtual Gfx::Color GetClearColor() = 0; + + //! Sets the global ambient color + virtual void SetGlobalAmbient(const Gfx::Color &color) = 0; + //! Returns the global ambient color + virtual Gfx::Color GetGlobalAmbient() = 0; + + //! Sets the fog parameters: mode, color, start distance, end distance and density (for exp models) + virtual void SetFogParams(Gfx::FogMode mode, const Gfx::Color &color, float start, float end, float density) = 0; + //! Returns the current fog parameters: mode, color, start distance, end distance and density (for exp models) + virtual void GetFogParams(Gfx::FogMode &mode, Gfx::Color &color, float &start, float &end, float &density) = 0; + + //! Sets the current cull mode + virtual void SetCullMode(Gfx::CullMode mode) = 0; + //! 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 + virtual Gfx::FillMode GetFillMode() = 0; +}; + +}; // namespace Gfx diff --git a/src/graphics/core/light.h b/src/graphics/core/light.h new file mode 100644 index 0000000..b787cb2 --- /dev/null +++ b/src/graphics/core/light.h @@ -0,0 +1,91 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * 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/. + +// light.h + +#pragma once + + +#include "graphics/core/color.h" +#include "math/vector.h" + + +namespace Gfx { + +/** + \enum LightType + \brief Type of light in 3D scene */ +enum LightType +{ + LIGHT_POINT, + LIGHT_SPOT, + LIGHT_DIRECTIONAL +}; + +/** + \struct Light + \brief Properties of light in 3D scene + + This structure was created as analog to DirectX's D3DLIGHT. */ +struct Light +{ + //! Type of light source + Gfx::LightType type; + //! Color of ambient light + Gfx::Color ambient; + //! Color of diffuse light + Gfx::Color diffuse; + //! Color of specular light + Gfx::Color specular; + //! Position in world space (for point & spot lights) + Math::Vector position; + //! Direction in world space (for directional & spot lights) + Math::Vector direction; + //! Constant attenuation factor + float attenuation0; + //! Linear attenuation factor + float attenuation1; + //! Quadratic attenuation factor + float attenuation2; + //! Angle of spotlight cone (0-90 degrees) + float spotAngle; + //! Intensity of spotlight (0 = uniform; 128 = most intense) + float spotIntensity; + + //! Constructor; calls LoadDefault() + Light() + { + LoadDefault(); + } + + //! Loads default values + void LoadDefault() + { + type = LIGHT_POINT; + ambient = Gfx::Color(0.4f, 0.4f, 0.4f); + diffuse = Gfx::Color(0.8f, 0.8f, 0.8f); + specular = Gfx::Color(1.0f, 1.0f, 1.0f); + position = Math::Vector(0.0f, 0.0f, 0.0f); + direction = Math::Vector(0.0f, 0.0f, 1.0f); + attenuation0 = 1.0f; + attenuation1 = attenuation2 = 0.0f; + spotAngle = 90.0f; + spotIntensity = 0.0f; + } +}; + +}; // namespace Gfx diff --git a/src/graphics/common/material.h b/src/graphics/core/material.h index f71923f..31b42f3 100644 --- a/src/graphics/common/material.h +++ b/src/graphics/core/material.h @@ -19,6 +19,9 @@ #pragma once +#include "graphics/core/color.h" + + namespace Gfx { /** diff --git a/src/graphics/core/texture.h b/src/graphics/core/texture.h new file mode 100644 index 0000000..8d6b082 --- /dev/null +++ b/src/graphics/core/texture.h @@ -0,0 +1,237 @@ +// * 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/. + +// texture.h + +#pragma once + +#include "math/intsize.h" + + +namespace Gfx { + +/** + \enum TexImgFormat + \brief Format of image data */ +enum TexImgFormat +{ + //! Try to determine automatically (may not work) + TEX_IMG_AUTO, + //! RGB triplet, 3 bytes + TEX_IMG_RGB, + //! BGR triplet, 3 bytes + TEX_IMG_BGR, + //! RGBA triplet, 4 bytes + TEX_IMG_RGBA, + //! BGRA triplet, 4 bytes + TEX_IMG_BGRA +}; + +/** + \enum TexMinFilter + \brief Texture minification 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 Texture magnification 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 +{ + //! Default operation on default params (modulate on computed & texture) + TEX_MIX_OPER_DEFAULT, + //! = Arg1 + TEX_MIX_OPER_REPLACE, + //! = Arg1 * Arg2 + TEX_MIX_OPER_MODULATE, + //! = Arg1 + Arg2 + TEX_MIX_OPER_ADD, + //! = Arg1 - Arg2 + TEX_MIX_OPER_SUBTRACT +}; + +/** + \enum TexMixArgument + \brief Multitexture mixing argument */ +enum TexMixArgument +{ + //! Color from current texture + TEX_MIX_ARG_TEXTURE, + //! Color computed by previous texture unit (current in DirectX; previous in OpenGL) + TEX_MIX_ARG_COMPUTED_COLOR, + //! (Source) color of textured fragment (diffuse in DirectX; primary color in OpenGL) + TEX_MIX_ARG_SRC_COLOR, + //! Constant color (texture factor in DirectX; texture env color in OpenGL) + TEX_MIX_ARG_FACTOR +}; + +/** + \struct TextureCreateParams + \brief Parameters for texture creation + + These params define how particular texture is created and later displayed. + They must be specified at texture creation time and cannot be changed later. */ +struct TextureCreateParams +{ + //! Whether to generate mipmaps + bool mipmap; + //! Format of source image data + Gfx::TexImgFormat format; + //! Minification filter + Gfx::TexMinFilter minFilter; + //! Magnification filter + Gfx::TexMagFilter magFilter; + + //! Constructor; calls LoadDefault() + TextureCreateParams() + { LoadDefault(); } + + //! Loads the default values + inline void LoadDefault() + { + format = Gfx::TEX_IMG_RGB; + mipmap = false; + + minFilter = Gfx::TEX_MIN_FILTER_NEAREST; + magFilter = Gfx::TEX_MAG_FILTER_NEAREST; + } +}; + +/** + \struct TextureStageParams + \brief Parameters for a texture unit + + These params define the behavior of texturing units (stages). + They can be changed freely and are feature of graphics engine, not any particular texture. */ +struct TextureStageParams +{ + //! 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; + //! Wrap mode for 1st tex coord + Gfx::TexWrapMode wrapS; + //! Wrap mode for 2nd tex coord + Gfx::TexWrapMode wrapT; + + //! Constructor; calls LoadDefault() + TextureStageParams() + { LoadDefault(); } + + //! Loads the default values + inline void LoadDefault() + { + colorOperation = Gfx::TEX_MIX_OPER_DEFAULT; + colorArg1 = Gfx::TEX_MIX_ARG_COMPUTED_COLOR; + colorArg2 = Gfx::TEX_MIX_ARG_TEXTURE; + + alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; + alphaArg1 = Gfx::TEX_MIX_ARG_COMPUTED_COLOR; + alphaArg2 = Gfx::TEX_MIX_ARG_TEXTURE; + + wrapS = wrapT = Gfx::TEX_WRAP_REPEAT; + } +}; + +/** + \struct Texture + \brief Info about a texture + + Identifies (through id) a texture created in graphics engine. + Also contains some additional data. */ +struct Texture +{ + //! Whether the texture (ID) is valid + bool valid; + //! ID of the texture in graphics engine + unsigned int id; + //! Size of texture + Math::IntSize size; + //! Whether the texture has alpha channel + bool alpha; + + Texture() + { + valid = false; + id = 0; + alpha = false; + } + + //! Comparator for use in texture maps and sets + inline bool operator<(const Gfx::Texture &other) const + { + // Invalid textures are always "less than" every other texture + + if ( (!valid) && (!other.valid) ) + return false; + + if (!valid) + return true; + + if (!other.valid) + return false; + + return id < other.id; + } + + //! Comparator + inline bool operator==(const Gfx::Texture &other) const + { + if (valid != other.valid) + return false; + if ( (!valid) && (!other.valid) ) + return true; + + return id == other.id; + } +}; + +}; // namespace Gfx diff --git a/src/graphics/core/vertex.h b/src/graphics/core/vertex.h new file mode 100644 index 0000000..b7fab1c --- /dev/null +++ b/src/graphics/core/vertex.h @@ -0,0 +1,141 @@ +// * 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/. + +// vertex.h + +#pragma once + + +#include "graphics/core/color.h" +#include "math/vector.h" +#include "math/point.h" + +#include <sstream> + +namespace Gfx { + +/** + * \struct Vertex + * \brief Vertex of a primitive + * + * This structure was created as analog to DirectX's D3DVERTEX. + * + * It contains: + * - vertex coordinates (x,y,z) as Math::Vector, + * - normal coordinates (nx,ny,nz) as Math::Vector + * - texture coordinates (u,v) as Math::Point. + */ +struct Vertex +{ + Math::Vector coord; + Math::Vector normal; + Math::Point texCoord; + + Vertex(Math::Vector aCoord = Math::Vector(), + Math::Vector aNormal = Math::Vector(), + Math::Point aTexCoord = Math::Point()) + : coord(aCoord), normal(aNormal), texCoord(aTexCoord) {} + + + //! Returns a string "(c: [...], n: [...], tc: [...])" + inline std::string ToString() const + { + std::stringstream s; + s.precision(3); + s << "(c: " << coord.ToString() << ", n: " << normal.ToString() + << ", tc: " << texCoord.ToString() << ")"; + return s.str(); + } +}; + +/** + * \struct VertexCol + * \brief Vertex with color information + * + * This structure was created as analog to DirectX's D3DLVERTEX. + * + * It contains: + * - vertex coordinates (x,y,z) as Math::Vector, + * - RGBA color as Gfx::Color, + * - RGBA specular color as Gfx::Color, + * - texture coordinates (u,v) as Math::Point. + */ +struct VertexCol +{ + Math::Vector coord; + Gfx::Color color; + Gfx::Color specular; + Math::Point texCoord; + + VertexCol(Math::Vector aCoord = Math::Vector(), + Gfx::Color aColor = Gfx::Color(), + Gfx::Color aSpecular = Gfx::Color(), + Math::Point aTexCoord = Math::Point()) + : coord(aCoord), color(aColor), specular(aSpecular), texCoord(aTexCoord) {} + + //! Returns a string "(c: [...], col: [...], sp: [...], tc: [...])" + inline std::string ToString() const + { + std::stringstream s; + s.precision(3); + s << "(c: " << coord.ToString() << ", col: " << color.ToString() << ", sp: " + << specular.ToString() << ", tc: " << texCoord.ToString() << ")"; + return s.str(); + } +}; + + +/** + * \struct VertexTex2 + * \brief Vertex with secondary texture coordinates + * + * In addition to fields from Gfx::Vector, it contains + * secondary texture coordinates (u2, v2) as Math::Point + */ +struct VertexTex2 +{ + Math::Vector coord; + Math::Vector normal; + Math::Point texCoord; + Math::Point texCoord2; + + VertexTex2(Math::Vector aCoord = Math::Vector(), + Math::Vector aNormal = Math::Vector(), + Math::Point aTexCoord = Math::Point(), + Math::Point aTexCoord2 = Math::Point()) + : coord(aCoord), normal(aNormal), texCoord(aTexCoord), texCoord2(aTexCoord2) {} + + //! Sets the fields from Gfx::Vertex with texCoord2 = (0,0) + void FromVertex(const Gfx::Vertex &v) + { + coord = v.coord; + normal = v.normal; + texCoord = v.texCoord; + texCoord2 = Math::Point(); + } + + //! Returns a string "(c: [...], n: [...], tc: [...], tc2: [...])" + inline std::string ToString() const + { + std::stringstream s; + s.precision(3); + s << "(c: " << coord.ToString() << ", n: " << normal.ToString() + << ", tc: " << texCoord.ToString() << ", tc2: " << texCoord2.ToString() << ")"; + return s.str(); + } +}; + +}; // namespace Gfx diff --git a/src/graphics/engine/README.txt b/src/graphics/engine/README.txt new file mode 100644 index 0000000..308b601 --- /dev/null +++ b/src/graphics/engine/README.txt @@ -0,0 +1,8 @@ +src/graphics/engine + +Graphics engine + +CEngine class and various other classes implementing the main features +of graphics engine from model loading to decorative particles + +Graphics operations are done on abstract interface from src/graphics/core diff --git a/src/graphics/engine/camera.cpp b/src/graphics/engine/camera.cpp new file mode 100644 index 0000000..c7ca503 --- /dev/null +++ b/src/graphics/engine/camera.cpp @@ -0,0 +1,1664 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * 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/. + +// camera.cpp + +#include "graphics/engine/camera.h" + +#include "common/iman.h" +#include "graphics/engine/engine.h" +#include "graphics/engine/terrain.h" +#include "graphics/engine/water.h" +#include "math/const.h" +#include "math/geometry.h" +#include "object/object.h" +#include "physics/physics.h" + + +//! Changes the level of transparency of an object and objects transported (battery & cargo) +void SetTransparency(CObject* obj, float value) +{ + obj->SetTransparency(value); + + CObject *fret = obj->GetFret(); + if (fret != NULL) + fret->SetTransparency(value); + + fret = obj->GetPower(); + if (fret != NULL) + fret->SetTransparency(value); +} + + + +Gfx::CCamera::CCamera(CInstanceManager* iMan) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_CAMERA, this); + + m_engine = static_cast<Gfx::CEngine*> ( m_iMan->SearchInstance(CLASS_ENGINE) ); + m_terrain = static_cast<Gfx::CTerrain*>( m_iMan->SearchInstance(CLASS_TERRAIN) ); + m_water = static_cast<Gfx::CWater*> ( m_iMan->SearchInstance(CLASS_WATER) ); + + m_type = Gfx::CAM_TYPE_FREE; + m_smooth = Gfx::CAM_SMOOTH_NORM; + m_cameraObj = 0; + + m_eyeDistance = 10.0f; + m_initDelay = 0.0f; + + m_actualEye = Math::Vector(0.0f, 0.0f, 0.0f); + m_actualLookat = Math::Vector(0.0f, 0.0f, 0.0f); + m_finalEye = Math::Vector(0.0f, 0.0f, 0.0f); + m_finalLookat = Math::Vector(0.0f, 0.0f, 0.0f); + m_normEye = Math::Vector(0.0f, 0.0f, 0.0f); + m_normLookat = Math::Vector(0.0f, 0.0f, 0.0f); + m_focus = 1.0f; + + m_rightDown = false; + m_rightPosInit = Math::Point(0.5f, 0.5f); + m_rightPosCenter = Math::Point(0.5f, 0.5f); + m_rightPosMove = Math::Point(0.5f, 0.5f); + + m_eyePt = Math::Vector(0.0f, 0.0f, 0.0f); + m_directionH = 0.0f; + m_directionV = 0.0f; + m_heightEye = 20.0f; + m_heightLookat = 0.0f; + m_speed = 2.0f; + + m_backDist = 0.0f; + m_backMin = 0.0f; + m_addDirectionH = 0.0f; + m_addDirectionV = 0.0f; + m_transparency = false; + + m_fixDist = 0.0f; + m_fixDirectionH = 0.0f; + m_fixDirectionV = 0.0f; + + m_visitGoal = Math::Vector(0.0f, 0.0f, 0.0f); + m_visitDist = 0.0f; + m_visitTime = 0.0f; + m_visitType = Gfx::CAM_TYPE_NULL; + m_visitDirectionH = 0.0f; + m_visitDirectionV = 0.0f; + + m_editHeight = 40.0f; + + m_remotePan = 0.0f; + m_remoteZoom = 0.0f; + + m_mouseDirH = 0.0f; + m_mouseDirV = 0.0f; + m_mouseMarging = 0.01f; + + m_motorTurn = 0.0f; + + m_centeringPhase = Gfx::CAM_PHASE_NULL; + m_centeringAngleH = 0.0f; + m_centeringAngleV = 0.0f; + m_centeringDist = 0.0f; + m_centeringCurrentH = 0.0f; + m_centeringCurrentV = 0.0f; + m_centeringTime = 0.0f; + m_centeringProgress = 0.0f; + + m_effectType = Gfx::CAM_EFFECT_NULL; + m_effectPos = Math::Vector(0.0f, 0.0f, 0.0f); + m_effectForce = 0.0f; + m_effectProgress = 0.0f; + m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); + + m_scriptEye = Math::Vector(0.0f, 0.0f, 0.0f); + m_scriptLookat = Math::Vector(0.0f, 0.0f, 0.0f); + + m_effect = true; + m_cameraScroll = true; + m_cameraInvertX = false; + m_cameraInvertY = false; +} + +Gfx::CCamera::~CCamera() +{ +} + +void Gfx::CCamera::SetEffect(bool enable) +{ + m_effect = enable; +} + +void Gfx::CCamera::SetCameraScroll(bool scroll) +{ + m_cameraScroll = scroll; +} + +void Gfx::CCamera::SetCameraInvertX(bool invert) +{ + m_cameraInvertX = invert; +} + +void Gfx::CCamera::SetCameraInvertY(bool invert) +{ + m_cameraInvertY = invert; +} + +float Gfx::CCamera::GetMotorTurn() +{ + if (m_type == Gfx::CAM_TYPE_BACK) + return m_motorTurn; + return 0.0f; +} + +void Gfx::CCamera::Init(Math::Vector eye, Math::Vector lookat, float delay) +{ + m_initDelay = delay; + + eye.y += m_terrain->GetFloorLevel(eye, true); + lookat.y += m_terrain->GetFloorLevel(lookat, true); + + m_type = Gfx::CAM_TYPE_FREE; + m_eyePt = eye; + + m_directionH = Math::RotateAngle(eye.x - lookat.x, eye.z - lookat.z) + Math::PI / 2.0f; + m_directionV = -Math::RotateAngle(Math::DistanceProjected(eye, lookat), eye.y - lookat.y); + + m_eyeDistance = 10.0f; + m_heightLookat = 10.0f; + m_backDist = 30.0f; + m_backMin = 10.0f; + m_addDirectionH = 0.0f; + m_addDirectionV = -Math::PI*0.05f; + m_fixDist = 50.0f; + m_fixDirectionH = Math::PI*0.25f; + m_fixDirectionV = -Math::PI*0.10f; + m_centeringPhase = Gfx::CAM_PHASE_NULL; + m_actualEye = m_eyePt; + m_actualLookat = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f); + m_finalEye = m_actualEye; + m_finalLookat = m_actualLookat; + m_scriptEye = m_actualEye; + m_scriptLookat = m_actualLookat; + m_focus = 1.00f; + m_remotePan = 0.0f; + m_remoteZoom = 0.0f; + + FlushEffect(); + FlushOver(); + SetType(Gfx::CAM_TYPE_FREE); +} + + +void Gfx::CCamera::SetObject(CObject* object) +{ + m_cameraObj = object; +} + +CObject* Gfx::CCamera::GetObject() +{ + return m_cameraObj; +} + +void Gfx::CCamera::SetType(CameraType type) +{ + m_remotePan = 0.0f; + m_remoteZoom = 0.0f; + + if ( (m_type == Gfx::CAM_TYPE_BACK) && m_transparency ) + { + for (int i = 0; i < 1000000; i++) + { + CObject* obj = static_cast<CObject*>( m_iMan->SearchInstance(CLASS_OBJECT, i) ); + if (obj == NULL) + break; + + if (obj->GetTruck()) + continue; // battery or cargo? + + SetTransparency(obj, 0.0f); // opaque object + } + } + m_transparency = false; + + if (type == Gfx::CAM_TYPE_INFO || + type == Gfx::CAM_TYPE_VISIT) // xx -> info ? + { + m_normEye = m_engine->GetEyePt(); + m_normLookat = m_engine->GetLookatPt(); + + m_engine->SetFocus(1.00f); // normal + m_type = type; + return; + } + + if (m_type == Gfx::CAM_TYPE_INFO || + m_type == Gfx::CAM_TYPE_VISIT) // info -> xx ? + { + m_engine->SetFocus(m_focus); // gives initial focus + m_type = type; + + Math::Vector upVec = Math::Vector(0.0f, 1.0f, 0.0f); + SetViewParams(m_normEye, m_normLookat, upVec); + return; + } + + if ( m_type == Gfx::CAM_TYPE_BACK && type == Gfx::CAM_TYPE_FREE ) // back -> free ? + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f); + + if ( m_type == Gfx::CAM_TYPE_BACK && type == Gfx::CAM_TYPE_EDIT ) // back -> edit ? + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -1.0f); + + if ( m_type == Gfx::CAM_TYPE_ONBOARD && type == Gfx::CAM_TYPE_FREE ) // onboard -> free ? + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f); + + if ( m_type == Gfx::CAM_TYPE_ONBOARD && type == Gfx::CAM_TYPE_EDIT ) // onboard -> edit ? + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f); + + if ( m_type == Gfx::CAM_TYPE_ONBOARD && type == Gfx::CAM_TYPE_EXPLO ) // onboard -> explo ? + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f); + + if ( m_type == Gfx::CAM_TYPE_BACK && type == Gfx::CAM_TYPE_EXPLO ) // back -> explo ? + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -20.0f); + + if ( type == Gfx::CAM_TYPE_FIX || + type == Gfx::CAM_TYPE_PLANE ) + AbortCentering(); // Special stops framing + + m_fixDist = 50.0f; + if ( type == Gfx::CAM_TYPE_PLANE ) + m_fixDist = 60.0f; + + if ( type == Gfx::CAM_TYPE_BACK ) + { + AbortCentering(); // Special stops framing + m_addDirectionH = 0.0f; + m_addDirectionV = -Math::PI*0.05f; + + ObjectType oType; + if ( m_cameraObj == 0 ) oType = OBJECT_NULL; + else oType = m_cameraObj->GetType(); + + m_backDist = 30.0f; + if ( oType == OBJECT_BASE ) m_backDist = 200.0f; + if ( oType == OBJECT_HUMAN ) m_backDist = 20.0f; + if ( oType == OBJECT_TECH ) m_backDist = 20.0f; + if ( oType == OBJECT_FACTORY ) m_backDist = 50.0f; + if ( oType == OBJECT_RESEARCH ) m_backDist = 40.0f; + if ( oType == OBJECT_DERRICK ) m_backDist = 40.0f; + if ( oType == OBJECT_REPAIR ) m_backDist = 35.0f; + if ( oType == OBJECT_DESTROYER) m_backDist = 35.0f; + if ( oType == OBJECT_TOWER ) m_backDist = 45.0f; + if ( oType == OBJECT_NUCLEAR ) m_backDist = 70.0f; + if ( oType == OBJECT_PARA ) m_backDist = 180.0f; + if ( oType == OBJECT_SAFE ) m_backDist = 50.0f; + if ( oType == OBJECT_HUSTON ) m_backDist = 120.0f; + + m_backMin = m_backDist/3.0f; + if ( oType == OBJECT_HUMAN ) m_backMin = 10.0f; + if ( oType == OBJECT_TECH ) m_backMin = 10.0f; + if ( oType == OBJECT_FACTORY ) m_backMin = 30.0f; + if ( oType == OBJECT_RESEARCH ) m_backMin = 20.0f; + if ( oType == OBJECT_NUCLEAR ) m_backMin = 32.0f; + if ( oType == OBJECT_PARA ) m_backMin = 40.0f; + if ( oType == OBJECT_SAFE ) m_backMin = 25.0f; + if ( oType == OBJECT_HUSTON ) m_backMin = 80.0f; + } + + if ( type != Gfx::CAM_TYPE_ONBOARD && m_cameraObj != 0 ) + m_cameraObj->SetGunGoalH(0.0f); // puts the cannon right + + if ( type == Gfx::CAM_TYPE_ONBOARD ) + m_focus = 1.50f; // Wide + else + m_focus = 1.00f; // normal + m_engine->SetFocus(m_focus); + + m_type = type; + + SetSmooth(Gfx::CAM_SMOOTH_NORM); +} + +CameraType Gfx::CCamera::GetType() +{ + return m_type; +} + +void Gfx::CCamera::SetSmooth(CameraSmooth type) +{ + m_smooth = type; +} + +CameraSmooth Gfx::CCamera::GetSmoth() +{ + return m_smooth; +} + +void Gfx::CCamera::SetDist(float dist) +{ + m_fixDist = dist; +} + +float Gfx::CCamera::GetDist() +{ + return m_fixDist; +} + +void Gfx::CCamera::SetFixDirection(float angle) +{ + m_fixDirectionH = angle; +} + +float Gfx::CCamera::GetFixDirection() +{ + return m_fixDirectionH; +} + +void Gfx::CCamera::SetRemotePan(float value) +{ + m_remotePan = value; +} + +float Gfx::CCamera::GetRemotePan() +{ + return m_remotePan; +} + +void Gfx::CCamera::SetRemoteZoom(float value) +{ + value = Math::Norm(value); + + if ( m_type == Gfx::CAM_TYPE_BACK ) + m_backDist = m_backMin + (200.0f - m_backMin) * value; + + if ( m_type == Gfx::CAM_TYPE_FIX || + m_type == Gfx::CAM_TYPE_PLANE ) + m_fixDist = 10.0f + (200.0f - 10.0f) * value; +} + +float Gfx::CCamera::GetRemoteZoom() +{ + if ( m_type == Gfx::CAM_TYPE_BACK ) + return (m_backDist - m_backMin) / (200.0f - m_backMin); + + if ( m_type == Gfx::CAM_TYPE_FIX || + m_type == Gfx::CAM_TYPE_PLANE ) + return (m_fixDist - 10.0f) / (200.0f - 10.0f); + + return 0.0f; +} + +void Gfx::CCamera::StartVisit(Math::Vector goal, float dist) +{ + m_visitType = m_type; + SetType(Gfx::CAM_TYPE_VISIT); + m_visitGoal = goal; + m_visitDist = dist; + m_visitTime = 0.0f; + m_visitDirectionH = 0.0f; + m_visitDirectionV = -Math::PI*0.10f; +} + +void Gfx::CCamera::StopVisit() +{ + SetType(m_visitType); // presents the initial type +} + +void Gfx::CCamera::GetCamera(Math::Vector &eye, Math::Vector &lookat) +{ + eye = m_eyePt; + lookat = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f); +} + +bool Gfx::CCamera::StartCentering(CObject *object, float angleH, float angleV, + float dist, float time) +{ + if (m_type != Gfx::CAM_TYPE_BACK) + return false; + if (object != m_cameraObj) + return false; + + if (m_centeringPhase != Gfx::CAM_PHASE_NULL) + return false; + + if (m_addDirectionH > Math::PI) + angleH = Math::PI * 2.0f - angleH; + + m_centeringPhase = Gfx::CAM_PHASE_START; + m_centeringAngleH = angleH; + m_centeringAngleV = angleV; + m_centeringDist = dist; + m_centeringCurrentH = 0.0f; + m_centeringCurrentV = 0.0f; + m_centeringTime = time; + m_centeringProgress = 0.0f; + + return true; +} + +bool Gfx::CCamera::StopCentering(CObject *object, float time) +{ + if (m_type != Gfx::CAM_TYPE_BACK) + return false; + if (object != m_cameraObj) + return false; + + if (m_centeringPhase != Gfx::CAM_PHASE_START && + m_centeringPhase != Gfx::CAM_PHASE_WAIT) + return false; + + m_centeringPhase = Gfx::CAM_PHASE_STOP; + + if (m_centeringAngleH != 99.9f) + m_centeringAngleH = m_centeringCurrentH; + + if (m_centeringAngleV != 99.9f) + m_centeringAngleV = m_centeringCurrentV; + + m_centeringTime = time; + m_centeringProgress = 0.0f; + + return true; +} + +void Gfx::CCamera::AbortCentering() +{ + if (m_type == Gfx::CAM_TYPE_INFO || + m_type == Gfx::CAM_TYPE_VISIT ) + return; + + if (m_centeringPhase == Gfx::CAM_PHASE_NULL) + return; + + m_centeringPhase = Gfx::CAM_PHASE_NULL; + + if ( m_centeringAngleH != 99.9f ) + m_addDirectionH = m_centeringCurrentH; + + if (m_centeringAngleV != 99.9f) + m_addDirectionV = m_centeringCurrentV; +} + +void Gfx::CCamera::FlushEffect() +{ + m_effectType = Gfx::CAM_EFFECT_NULL; + m_effectForce = 0.0f; + m_effectProgress = 0.0f; + m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); +} + +void Gfx::CCamera::StartEffect(CameraEffect effect, Math::Vector pos, float force) +{ + if ( !m_effect ) return; + + m_effectType = effect; + m_effectPos = pos; + m_effectForce = force; + m_effectProgress = 0.0f; +} + +void Gfx::CCamera::EffectFrame(const Event &event) +{ + if (m_type == Gfx::CAM_TYPE_INFO || + m_type == Gfx::CAM_TYPE_VISIT) + return; + + if (m_effectType == Gfx::CAM_EFFECT_NULL) + return; + + m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); + + float force = m_effectForce; + + if ( m_effectType == Gfx::CAM_EFFECT_TERRAFORM ) + { + m_effectProgress += event.rTime * 0.7f; + m_effectOffset.x = (Math::Rand() - 0.5f) * 10.0f; + m_effectOffset.y = (Math::Rand() - 0.5f) * 10.0f; + m_effectOffset.z = (Math::Rand() - 0.5f) * 10.0f; + + force *= 1.0f-m_effectProgress; + } + + if ( m_effectType == Gfx::CAM_EFFECT_EXPLO ) + { + m_effectProgress += event.rTime * 1.0f; + m_effectOffset.x = (Math::Rand() - 0.5f) *5.0f; + m_effectOffset.y = (Math::Rand() - 0.5f) * 5.0f; + m_effectOffset.z = (Math::Rand() - 0.5f) * 5.0f; + + force *= 1.0f-m_effectProgress; + } + + if ( m_effectType == Gfx::CAM_EFFECT_SHOT ) + { + m_effectProgress += event.rTime * 1.0f; + m_effectOffset.x = (Math::Rand() - 0.5f) * 2.0f; + m_effectOffset.y = (Math::Rand() - 0.5f) * 2.0f; + m_effectOffset.z = (Math::Rand() - 0.5f) * 2.0f; + + force *= 1.0f-m_effectProgress; + } + + if ( m_effectType == Gfx::CAM_EFFECT_CRASH ) + { + m_effectProgress += event.rTime * 5.0f; + m_effectOffset.y = sinf(m_effectProgress * Math::PI) * 1.5f; + m_effectOffset.x = (Math::Rand() - 0.5f) * 1.0f * (1.0f - m_effectProgress); + m_effectOffset.z = (Math::Rand() - 0.5f) * 1.0f * (1.0f - m_effectProgress); + } + + if ( m_effectType == Gfx::CAM_EFFECT_VIBRATION ) + { + m_effectProgress += event.rTime * 0.1f; + m_effectOffset.y = (Math::Rand() - 0.5f) * 1.0f * (1.0f - m_effectProgress); + m_effectOffset.x = (Math::Rand() - 0.5f) * 1.0f * (1.0f - m_effectProgress); + m_effectOffset.z = (Math::Rand() - 0.5f) * 1.0f * (1.0f - m_effectProgress); + } + + if ( m_effectType == Gfx::CAM_EFFECT_PET ) + { + m_effectProgress += event.rTime *5.0f; + m_effectOffset.x = (Math::Rand() - 0.5f) * 0.2f; + m_effectOffset.y = (Math::Rand() - 0.5f) * 2.0f; + m_effectOffset.z = (Math::Rand() - 0.5f) * 0.2f; + } + + float dist = Math::Distance(m_eyePt, m_effectPos); + dist = Math::Norm((dist - 100.f) / 100.0f); + + force *= 1.0f-dist; +#if _TEEN + force *= 2.0f; +#endif + m_effectOffset *= force; + + if (m_effectProgress >= 1.0f) + FlushEffect(); +} + +void Gfx::CCamera::FlushOver() +{ + m_overType = Gfx::CAM_OVER_EFFECT_NULL; + m_overColorBase = Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f); // black + m_engine->SetOverColor(); // nothing +} + +void Gfx::CCamera::SetOverBaseColor(Gfx::Color color) +{ + m_overColorBase = color; +} + +void Gfx::CCamera::StartOver(Gfx::CameraOverEffect effect, Math::Vector pos, float force) +{ + m_overType = effect; + m_overTime = 0.0f; + + float decay; + if (m_overType == Gfx::CAM_OVER_EFFECT_LIGHTNING) + decay = 400.0f; + else + decay = 100.0f; + + float dist = Math::Distance(m_eyePt, pos); + dist = (dist - decay) / decay; + if (dist < 0.0f) dist = 0.0f; + if (dist > 1.0f) dist = 1.0f; + + m_overForce = force * (1.0f - dist); + + if (m_overType == Gfx::CAM_OVER_EFFECT_BLOOD) + { + m_overColor = Gfx::Color(0.8f, 0.1f, 0.1f); // red + m_overMode = Gfx::ENG_RSTATE_TCOLOR_BLACK; + + m_overFadeIn = 0.4f; + m_overFadeOut = 0.8f; + m_overForce = 1.0f; + } + + if ( m_overType == Gfx::CAM_OVER_EFFECT_FADEIN_WHITE ) + { + m_overColor = Gfx::Color(1.0f, 1.0f, 1.0f); // white + m_overMode = Gfx::ENG_RSTATE_TCOLOR_BLACK; + + m_overFadeIn = 0.0f; + m_overFadeOut = 20.0f; + m_overForce = 1.0f; + } + + if ( m_overType == Gfx::CAM_OVER_EFFECT_FADEOUT_WHITE ) + { + m_overColor = Gfx::Color(1.0f, 1.0f, 1.0f); // white + m_overMode = Gfx::ENG_RSTATE_TCOLOR_BLACK; + + m_overFadeIn = 6.0f; + m_overFadeOut = 100000.0f; + m_overForce = 1.0f; + } + + if ( m_overType == Gfx::CAM_OVER_EFFECT_FADEOUT_BLACK ) + { + m_overColor = m_engine->GetFogColor(1); // fog color underwater + m_overMode = Gfx::ENG_RSTATE_TTEXTURE_WHITE; + + m_overFadeIn = 4.0f; + m_overFadeOut = 100000.0f; + m_overForce = 1.0f; + } + + if ( m_overType == Gfx::CAM_OVER_EFFECT_LIGHTNING ) + { + m_overColor = Gfx::Color(0.9f, 1.0f, 1.0f); // white-cyan + m_overMode = Gfx::ENG_RSTATE_TCOLOR_BLACK; + + m_overFadeIn = 0.0f; + m_overFadeOut = 1.0f; + } +} + +void Gfx::CCamera::OverFrame(const Event &event) +{ + if (m_type == Gfx::CAM_TYPE_INFO || + m_type == Gfx::CAM_TYPE_VISIT) + return; + + if (m_overType == Gfx::CAM_OVER_EFFECT_NULL) + return; + + m_overTime += event.rTime; + + if (m_overType == Gfx::CAM_OVER_EFFECT_LIGHTNING) + { + Gfx::Color color; + if (rand() % 2 == 0) + { + color.r = m_overColor.r * m_overForce; + color.g = m_overColor.g * m_overForce; + color.b = m_overColor.b * m_overForce; + } + else + { + color = Gfx::Color(0.0f. 0.0f, 0.0f); + } + color.a = 0.0f; + m_engine->SetOverColor(color, m_overMode); + } + else + { + if ( (m_overFadeIn > 0.0f) && (m_overTime < m_overFadeIn) ) + { + float intensity = m_overTime / m_overFadeIn; + intensity *= m_overForce; + + Gfx::Color color; + if (m_overMode == Gfx::ENG_RSTATE_TCOLOR_WHITE) + { + color.r = 1.0f - (1.0f - m_overColor.r) * intensity; + color.g = 1.0f - (1.0f - m_overColor.g) * intensity; + color.b = 1.0f - (1.0f - m_overColor.b) * intensity; + } + else + { + color.r = m_overColor.r * intensity; + color.g = m_overColor.g * intensity; + color.b = m_overColor.b * intensity; + + color.r = 1.0f - (1.0f - color.r) * (1.0f - m_overColorBase.r); + color.g = 1.0f - (1.0f - color.g) * (1.0f - m_overColorBase.g); + color.b = 1.0f - (1.0f - color.b) * (1.0f - m_overColorBase.b); + } + color.a = 0.0f; + m_engine->SetOverColor(color, m_overMode); + } + else if ( (m_overFadeOut > 0.0f) && (m_overTime - m_overFadeIn < m_overFadeOut) ) + { + float intensity = 1.0f - (m_overTime - m_overFadeIn) / m_overFadeOut; + intensity *= m_overForce; + + Gfx::Color color; + if (m_overMode == Gfx::ENG_RSTATE_TCOLOR_WHITE) + { + color.r = 1.0f-(1.0f-m_overColor.r) * intensity; + color.g = 1.0f-(1.0f-m_overColor.g) * intensity; + color.b = 1.0f-(1.0f-m_overColor.b) * intensity; + } + else + { + color.r = m_overColor.r * intensity; + color.g = m_overColor.g * intensity; + color.b = m_overColor.b * intensity; + + color.r = 1.0f - (1.0f - color.r)*(1.0f - m_overColorBase.r); + color.g = 1.0f - (1.0f - color.g)*(1.0f - m_overColorBase.g); + color.b = 1.0f - (1.0f - color.b)*(1.0f - m_overColorBase.b); + } + color.a = 0.0f; + m_engine->SetOverColor(color, m_overMode); + } + } + + if ( m_overTime >= m_overFadeIn+m_overFadeOut ) + { + FlushOver(); + return; + } +} + +void Gfx::CCamera::FixCamera() +{ + m_initDelay = 0.0f; + m_actualEye = m_finalEye = m_scriptEye; + m_actualLookat = m_finalLookat = m_scriptLookat; + SetViewTime(m_scriptEye, m_scriptLookat, 0.0f); +} + +void Gfx::CCamera::SetViewTime(const Math::Vector &eyePt, + const Math::Vector &lookatPt, + float rTime) +{ + Math::Vector eye, lookat; + + if (m_type == Gfx::CAM_TYPE_INFO) + { + eye = eyePt; + lookat = lookatPt; + } + else + { + if (m_initDelay > 0.0f) + { + m_initDelay -= rTime; + if (m_initDelay < 0.0f) + m_initDelay = 0.0f; + rTime /= 1.0f+m_initDelay; + } + + eye = eyePt; + lookat = lookatPt; + if ( !IsCollision(eye, lookat) ) + { + m_finalEye = eye; + m_finalLookat = lookat; + } + + float prog = 0.0f; + float dist = Math::Distance(m_finalEye, m_actualEye); + + if (m_smooth == Gfx::CAM_SMOOTH_NONE) prog = dist; + if (m_smooth == Gfx::CAM_SMOOTH_NORM) prog = powf(dist, 1.5f) * rTime * 0.5f; + if (m_smooth == Gfx::CAM_SMOOTH_HARD) prog = powf(dist, 1.0f) * rTime * 4.0f; + if (m_smooth == Gfx::CAM_SMOOTH_SPEC) prog = powf(dist, 1.0f) * rTime * 0.05f; + if (dist == 0.0f) + { + m_actualEye = m_finalEye; + } + else + { + if (prog > dist) + prog = dist; + m_actualEye = (m_finalEye - m_actualEye) / dist * prog + m_actualEye; + } + + dist = Math::Distance(m_finalLookat, m_actualLookat); + if ( m_smooth == Gfx::CAM_SMOOTH_NONE ) prog = dist; + if ( m_smooth == Gfx::CAM_SMOOTH_NORM ) prog = powf(dist, 1.5f) * rTime * 2.0f; + if ( m_smooth == Gfx::CAM_SMOOTH_HARD ) prog = powf(dist, 1.0f) * rTime * 4.0f; + if ( m_smooth == Gfx::CAM_SMOOTH_SPEC ) prog = powf(dist, 1.0f) * rTime * 4.0f; + if ( dist == 0.0f ) + { + m_actualLookat = m_finalLookat; + } + else + { + if (prog > dist) + prog = dist; + m_actualLookat = (m_finalLookat - m_actualLookat) / dist * prog + m_actualLookat; + } + + eye = m_effectOffset+m_actualEye; + m_water->AdjustEye(eye); + + float h = m_terrain->GetFloorLevel(eye); + if (eye.y < h + 4.0f) + eye.y = h + 4.0f; + + lookat = m_effectOffset+m_actualLookat; + } + + Math::Vector upVec = Math::Vector(0.0f, 1.0f, 0.0f); + SetViewParams(eye, lookat, upVec); +} + +bool Gfx::CCamera::IsCollision(Math::Vector &eye, Math::Vector lookat) +{ + if (m_type == Gfx::CAM_TYPE_BACK ) return IsCollisionBack(eye, lookat); + if (m_type == Gfx::CAM_TYPE_FIX ) return IsCollisionFix (eye, lookat); + if (m_type == Gfx::CAM_TYPE_PLANE) return IsCollisionFix (eye, lookat); + return false; +} + +bool Gfx::CCamera::IsCollisionBack(Math::Vector &eye, Math::Vector lookat) +{ + ObjectType iType; + if (m_cameraObj == NULL) + iType = OBJECT_NULL; + else + iType = m_cameraObj->GetType(); + + Math::Vector min; + min.x = Math::Min(m_actualEye.x, m_actualLookat.x); + min.y = Math::Min(m_actualEye.y, m_actualLookat.y); + min.z = Math::Min(m_actualEye.z, m_actualLookat.z); + + Math::Vector max; + max.x = Math::Max(m_actualEye.x, m_actualLookat.x); + max.y = Math::Max(m_actualEye.y, m_actualLookat.y); + max.z = Math::Max(m_actualEye.z, m_actualLookat.z); + + m_transparency = false; + + for (int i = 0 ;i < 1000000; i++) + { + CObject *obj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if (obj == NULL) break; + + if (obj->GetTruck()) continue; // battery or cargo? + + SetTransparency(obj, 0.0f); // opaque object + + if (obj == m_cameraObj) continue; + + if ( iType == OBJECT_BASE || // building? + iType == OBJECT_DERRICK || + iType == OBJECT_FACTORY || + iType == OBJECT_STATION || + iType == OBJECT_CONVERT || + iType == OBJECT_REPAIR || + iType == OBJECT_DESTROYER|| + iType == OBJECT_TOWER || + iType == OBJECT_RESEARCH || + iType == OBJECT_RADAR || + iType == OBJECT_ENERGY || + iType == OBJECT_LABO || + iType == OBJECT_NUCLEAR || + iType == OBJECT_PARA || + iType == OBJECT_SAFE || + iType == OBJECT_HUSTON ) continue; + + ObjType oType = obj->GetType(); + if ( oType == OBJECT_HUMAN || + oType == OBJECT_TECH || + oType == OBJECT_TOTO || + oType == OBJECT_FIX || + oType == OBJECT_FRET || + oType == OBJECT_ANT || + oType == OBJECT_SPIDER || + oType == OBJECT_BEE || + oType == OBJECT_WORM ) continue; + + Math::Vector oPos; + float oRadius = 0.0f; + obj->GetGlobalSphere(oPos, oRadius); + if ( oRadius <= 2.0f ) continue; // ignores small objects + + if ( oPos.x+oRadius < min.x || + oPos.y+oRadius < min.y || + oPos.z+oRadius < min.z || + oPos.x-oRadius > max.x || + oPos.y-oRadius > max.y || + oPos.z-oRadius > max.z ) continue; + + Math::Vector proj = Projection(m_actualEye, m_actualLookat, oPos); + float dpp = Math::Distance(proj, oPos); + if ( dpp > oRadius ) continue; + + if ( oType == OBJECT_FACTORY ) + { + float angle = Math::RotateAngle(m_actualEye.x-oPos.x, oPos.z-m_actualEye.z); // CW ! + angle = Math::Direction(angle, obj->GetAngleY(0)); + if ( fabs(angle) < 30.0f*Math::PI/180.0f ) continue; // in the gate? + } + + float del = Math::Distance(m_actualEye, m_actualLookat); + if (oType == OBJECT_FACTORY) + del += oRadius; + + float len = Math::Distance(m_actualEye, proj); + if (len > del) continue; + + SetTransparency(obj, 1.0f); // transparent object + m_transparency = true; + } + return false; +} + +bool Gfx::CCamera::IsCollisionFix(Math::Vector &eye, Math::Vector lookat) +{ + for (int i = 0; i < 1000000; i++) + { + CObject *obj = static_cast<CObject*>( m_iMan->SearchInstance(CLASS_OBJECT, i) ); + if (obj == NULL) break; + + if (obj == m_cameraObj) continue; + + ObjectType type = obj->GetType(); + if ( type == OBJECT_TOTO || + type == OBJECT_FRET || + type == OBJECT_STONE || + type == OBJECT_URANIUM || + type == OBJECT_METAL || + type == OBJECT_POWER || + type == OBJECT_ATOMIC || + type == OBJECT_BULLET || + type == OBJECT_BBOX || + type == OBJECT_KEYa || + type == OBJECT_KEYb || + type == OBJECT_KEYc || + type == OBJECT_KEYd || + type == OBJECT_ANT || + type == OBJECT_SPIDER || + type == OBJECT_BEE || + type == OBJECT_WORM ) continue; + + Math::Vector objPos; + float objRadius = 0.0f; + obj->GetGlobalSphere(objPos, objRadius); + if (objRadius == 0.0f) continue; + + float dist = Math::Distance(eye, objPos); + if (dist < objRadius) + { + dist = Math::Distance(eye, lookat); + Math::Vector proj = Projection(eye, lookat, objPos); + eye = (lookat - eye) * objRadius / dist + proj; + return false; + } + } + return false; +} + +bool Gfx::CCamera::EventProcess(const Event &event) +{ + switch (event.type) + { + // TODO: frame update event + case EVENT_FRAME: + EventFrame(event); + break; + + case EVENT_MOUSE_MOVE: + EventMouseMove(event); + break; + + case EVENT_KEY_DOWN: + // TODO: mouse wheel event + if ( event.param == VK_WHEELUP ) EventMouseWheel(+1); + if ( event.param == VK_WHEELDOWN ) EventMouseWheel(-1); + break; + + default: + break; + } + return true; +} + +bool Gfx::CCamera::EventMouseMove(const Event &event) +{ + m_mousePos = event.pos; + return true; +} + +void Gfx::CCamera::EventMouseWheel(int dir) +{ + if (m_type == Gfx::CAM_TYPE_BACK) + { + if (dir > 0) + { + m_backDist -= 8.0f; + if (m_backDist < m_backMin) + m_backDist = m_backMin; + } + if (dir < 0) + { + m_backDist += 8.0f; + if (m_backDist > 200.0f) + m_backDist = 200.0f; + } + } + + if ( m_type == Gfx::CAM_TYPE_FIX || + m_type == Gfx::CAM_TYPE_PLANE ) + { + if (dir > 0) + { + m_fixDist -= 8.0f; + if (m_fixDist < 10.0f) + m_fixDist = 10.0f; + } + if (dir < 0) + { + m_fixDist += 8.0f; + if (m_fixDist > 200.0f) + m_fixDist = 200.0f; + } + } + + if ( m_type == Gfx::CAM_TYPE_VISIT ) + { + if (dir > 0) + { + m_visitDist -= 8.0f; + if (m_visitDist < 20.0f) + m_visitDist = 20.0f; + } + if (dir < 0) + { + m_visitDist += 8.0f; + if (m_visitDist > 200.0f) + m_visitDist = 200.0f; + } + } +} + +bool Gfx::CCamera::EventFrame(const Event &event) +{ + EffectFrame(event); + OverFrame(event); + + if (m_type == Gfx::CAM_TYPE_FREE) + return EventFrameFree(event); + + if (m_type == Gfx::CAM_TYPE_EDIT) + return EventFrameEdit(event); + + if (m_type == Gfx::CAM_TYPE_DIALOG) + return EventFrameDialog(event); + + if (m_type == Gfx::CAM_TYPE_BACK) + return EventFrameBack(event); + + if (m_type == Gfx::CAM_TYPE_FIX || + m_type == Gfx::CAM_TYPE_PLANE) + return EventFrameFix(event); + + if (m_type == Gfx::CAM_TYPE_EXPLO) + return EventFrameExplo(event); + + if (m_type == Gfx::CAM_TYPE_ONBOARD) + return EventFrameOnBoard(event); + + if (m_type == Gfx::CAM_TYPE_SCRIPT) + return EventFrameScript(event); + + if (m_type == Gfx::CAM_TYPE_INFO) + return EventFrameInfo(event); + + if (m_type == Gfx::CAM_TYPE_VISIT) + return EventFrameVisit(event); + + return true; +} + +Gfx::EngineMouseType Gfx::CCamera::GetMouseDef(Math::Point pos) +{ + Gfx::EngineMouseType type = Gfx::ENG_MOUSE_NORM; + m_mousePos = pos; + + if (m_type == Gfx::CAM_TYPE_INFO) + return type; + + if (m_rightDown) // the right button pressed? + { + m_rightPosMove.x = pos.x - m_rightPosCenter.x; + m_rightPosMove.y = pos.y - m_rightPosCenter.y; + type = Gfx::ENG_MOUSE_MOVE; + } + else + { + if (!m_cameraScroll) + return type; + + m_mouseDirH = 0.0f; + m_mouseDirV = 0.0f; + + if (pos.x < m_mouseMarging) + m_mouseDirH = pos.x / m_mouseMarging - 1.0f; + + if (pos.x > 1.0f - m_mouseMarging) + m_mouseDirH = 1.0f - (1.0f - pos.x) / m_mouseMarging; + + if (pos.y < m_mouseMarging) + m_mouseDirV = pos.y / m_mouseMarging - 1.0f; + + if (pos.y > 1.0f-m_mouseMarging) + m_mouseDirV = 1.0f - (1.0f - pos.y) / m_mouseMarging; + + if ( m_type == Gfx::CAM_TYPE_FREE || + m_type == Gfx::CAM_TYPE_EDIT || + m_type == Gfx::CAM_TYPE_BACK || + m_type == Gfx::CAM_TYPE_FIX || + m_type == Gfx::CAM_TYPE_PLANE || + m_type == Gfx::CAM_TYPE_EXPLO ) + { + if (m_mouseDirH > 0.0f) + type = Gfx::ENG_MOUSE_SCROLLR; + if (m_mouseDirH < 0.0f) + type = Gfx::ENG_MOUSE_SCROLLL; + } + + if ( m_type == Gfx::CAM_TYPE_FREE || + m_type == Gfx::CAM_TYPE_EDIT ) + { + if (m_mouseDirV > 0.0f) + type = Gfx::ENG_MOUSE_SCROLLU; + if (m_mouseDirV < 0.0f) + type = Gfx::ENG_MOUSE_SCROLLD; + } + + if (m_cameraInvertX) + m_mouseDirH = -m_mouseDirH; + } + + return type; +} + +bool Gfx::CCamera::EventFrameFree(const Event &event) +{ + float factor = m_heightEye * 0.5f + 30.0f; + + if ( m_mouseDirH != 0.0f ) + m_directionH -= m_mouseDirH * event.rTime * 0.7f * m_speed; + if ( m_mouseDirV != 0.0f ) + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV * event.rTime * factor * m_speed); + + // Up/Down + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, event.axeY * event.rTime * factor * m_speed); + + // Left/Right + if ( event.keyState & KS_CONTROL ) + { + if ( event.axeX < 0.0f ) + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH + Math::PI / 2.0f, m_directionV, -event.axeX * event.rTime * factor * m_speed); + if ( event.axeX > 0.0f ) + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH - Math::PI / 2.0f, m_directionV, event.axeX * event.rTime * factor * m_speed); + } + else + { + m_directionH -= event.axeX * event.rTime * 0.7f * m_speed; + } + + // PageUp/PageDown + if ( event.keyState & KS_NUMMINUS ) + { + if (m_heightEye < 500.0f) + m_heightEye += event.rTime * factor * m_speed; + } + if ( event.keyState & KS_NUMPLUS ) + { + if (m_heightEye > -2.0f) + m_heightEye -= event.rTime * factor * m_speed; + } + + m_terrain->ValidPosition(m_eyePt, 10.0f); + + if (m_terrain->MoveOnFloor(m_eyePt, true)) + { + m_eyePt.y += m_heightEye; + + Math::Vector pos = m_eyePt; + if (m_terrain->MoveOnFloor(pos, true)) + { + pos.y -= 2.0f; + if (m_eyePt.y < pos.y) + m_eyePt.y = pos.y; + } + + } + + Math::Vector lookatPt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f); + + if (m_terrain->MoveOnFloor(lookatPt, true)) + lookatPt.y += m_heightLookat; + + SetViewTime(m_eyePt, lookatPt, event.rTime); + + return true; +} + +bool Gfx::CCamera::EventFrameEdit(const Event &event) +{ + float factor = m_editHeight * 0.5f + 30.0f; + + if (m_mouseDirH != 0.0f) + m_directionH -= m_mouseDirH * event.rTime * 0.7f * m_speed; + if (m_mouseDirV != 0.0f) + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV * event.rTime * factor * m_speed); + + if (m_cameraScroll) + { + // Left/Right. + m_fixDirectionH += m_mouseDirH * event.rTime * 1.0f * m_speed; + m_fixDirectionH = Math::NormAngle(m_fixDirectionH); + } + + m_terrain->ValidPosition(m_eyePt, 10.0f); + + if (m_terrain->MoveOnFloor(m_eyePt, false)) + { + m_eyePt.y += m_editHeight; + + Math::Vector pos = m_eyePt; + if (m_terrain->MoveOnFloor(pos, false)) + { + pos.y += 2.0f; + if (m_eyePt.y < pos.y) + m_eyePt.y = pos.y; + } + + } + + Math::Vector lookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f ); + + if ( m_terrain->MoveOnFloor(lookatPt, true)) + lookatPt.y += m_heightLookat; + + SetViewTime(m_eyePt, lookatPt, event.rTime); + + return true; +} + +bool Gfx::CCamera::EventFrameDialog(const Event &event) +{ + return true; +} + +bool Gfx::CCamera::EventFrameBack(const Event &event) +{ + ObjectType type; + if (m_cameraObj == NULL) + type = OBJECT_NULL; + else + type = m_cameraObj->GetType(); + + // +/-. + if (event.keyState & KS_NUMPLUS) + { + m_backDist -= event.rTime * 30.0f * m_speed; + if (m_backDist < m_backMin) m_backDist = m_backMin; + } + if (event.keyState & KS_NUMMINUS) + { + m_backDist += event.rTime * 30.0f * m_speed; + if (m_backDist > 200.0f) m_backDist = 200.0f; + } + + m_motorTurn = 0.0f; + + if (m_rightDown) + { + m_addDirectionH = m_rightPosMove.x * 6.0f; + m_addDirectionV = -m_rightPosMove.y * 2.0f; + } + else + { + if (m_cameraScroll) + { + // Left/Right + m_addDirectionH += m_mouseDirH * event.rTime * 1.0f * m_speed; + m_addDirectionH = Math::NormAngle(m_addDirectionH); + } + } + + if ((m_mouseDirH != 0) || (m_mouseDirV != 0)) + AbortCentering(); // special stops framing + + // Increase the special framework + float centeringH = 0.0f; + float centeringV = 0.0f; + float centeringD = 0.0f; + + if (m_centeringPhase == Gfx::CAM_PHASE_START) + { + m_centeringProgress += event.rTime / m_centeringTime; + if (m_centeringProgress > 1.0f) m_centeringProgress = 1.0f; + centeringH = m_centeringProgress; + centeringV = m_centeringProgress; + centeringD = m_centeringProgress; + if (m_centeringProgress >= 1.0f) + m_centeringPhase = Gfx::CAM_PHASE_WAIT; + } + + if (m_centeringPhase == Gfx::CAM_PHASE_WAIT) + { + centeringH = 1.0f; + centeringV = 1.0f; + centeringD = 1.0f; + } + + if (m_centeringPhase == Gfx::CAM_PHASE_STOP) + { + m_centeringProgress += event.rTime / m_centeringTime; + if (m_centeringProgress > 1.0f) m_centeringProgress = 1.0f; + centeringH = 1.0f-m_centeringProgress; + centeringV = 1.0f-m_centeringProgress; + centeringD = 1.0f-m_centeringProgress; + if (m_centeringProgress >= 1.0f) + m_centeringPhase = Gfx::CAM_PHASE_NULL; + } + + if (m_centeringAngleH == 99.9f) centeringH = 0.0f; + if (m_centeringAngleV == 99.9f) centeringV = 0.0f; + if (m_centeringDist == 0.0f) centeringD = 0.0f; + + if (m_cameraObj != NULL) + { + Math::Vector lookatPt = m_cameraObj->GetPosition(0); + if (type == OBJECT_BASE ) lookatPt.y += 40.0f; + else if (type == OBJECT_HUMAN) lookatPt.y += 1.0f; + else if (type == OBJECT_TECH ) lookatPt.y += 1.0f; + else lookatPt.y += 4.0f; + + float h = -m_cameraObj->GetAngleY(0); // angle vehicle / building + + if ( type == OBJECT_DERRICK || + type == OBJECT_FACTORY || + type == OBJECT_REPAIR || + type == OBJECT_DESTROYER|| + type == OBJECT_STATION || + type == OBJECT_CONVERT || + type == OBJECT_TOWER || + type == OBJECT_RESEARCH || + type == OBJECT_RADAR || + type == OBJECT_INFO || + type == OBJECT_ENERGY || + type == OBJECT_LABO || + type == OBJECT_NUCLEAR || + type == OBJECT_PARA || + type == OBJECT_SAFE || + type == OBJECT_HUSTON || + type == OBJECT_START || + type == OBJECT_END ) // building? + { + h += Math::PI * 0.20f; // nearly face + } + else // vehicle? + { + h += Math::PI; // back + } + h = Math::NormAngle(h)+m_remotePan; + float v = 0.0f; //? + + h += m_centeringCurrentH; + h += m_addDirectionH * (1.0f - centeringH); + h = Math::NormAngle(h); + + if (type == OBJECT_MOBILEdr) // designer? + v -= 0.3f; // Camera top + + v += m_centeringCurrentV; + v += m_addDirectionV * (1.0f - centeringV); + + float d = m_backDist; + d += m_centeringDist * centeringD; + + m_centeringCurrentH = m_centeringAngleH * centeringH; + m_centeringCurrentV = m_centeringAngleV * centeringV; + + m_eyePt = RotateView(lookatPt, h, v, d); + + CPhysics* physics = m_cameraObj->GetPhysics(); + if ( (physics != NULL) && physics->GetLand() ) // ground? + { + Math::Vector pos = lookatPt + (lookatPt - m_eyePt); + float floor = m_terrain->GetFloorHeight(pos) - 4.0f; + if (floor > 0.0f) + m_eyePt.y += floor; // shows the descent in front + } + + m_eyePt = ExcludeTerrain(m_eyePt, lookatPt, h, v); + m_eyePt = ExcludeObject(m_eyePt, lookatPt, h, v); + + SetViewTime(m_eyePt, lookatPt, event.rTime); + + m_directionH = h + Math::PI / 2.0f; + m_directionV = v; + } + + return true; +} + +bool Gfx::CCamera::EventFrameFix(const Event &event) +{ + // +/-. + if (event.keyState & KS_NUMPLUS) + { + m_fixDist -= event.rTime * 30.0f * m_speed; + if (m_fixDist < 10.0f) m_fixDist = 10.0f; + } + if (event.keyState & KS_NUMMINUS) + { + m_fixDist += event.rTime * 30.0f * m_speed; + if (m_fixDist > 200.0f) m_fixDist = 200.0f; + } + + if (m_cameraScroll) + { + // Left/Right + m_fixDirectionH += m_mouseDirH * event.rTime * 1.0f * m_speed; + m_fixDirectionH = Math::NormAngle(m_fixDirectionH); + } + + if ((m_mouseDirH != 0) || (m_mouseDirV != 0)) + AbortCentering(); // special stops framing + + if (m_cameraObj != NULL) + { + Math::Vector lookatPt = m_cameraObj->GetPosition(0); + + float h = m_fixDirectionH + m_remotePan; + float v = m_fixDirectionV; + + float d = m_fixDist; + m_eyePt = RotateView(lookatPt, h, v, d); + if (m_type == Gfx::CAM_TYPE_PLANE) m_eyePt.y += m_fixDist / 2.0f; + m_eyePt = ExcludeTerrain(m_eyePt, lookatPt, h, v); + m_eyePt = ExcludeObject(m_eyePt, lookatPt, h, v); + + SetViewTime(m_eyePt, lookatPt, event.rTime); + + m_directionH = h + Math::PI / 2.0f; + m_directionV = v; + } + + return true; +} + +bool Gfx::CCamera::EventFrameExplo(const Event &event) +{ + float factor = m_heightEye * 0.5f + 30.0f; + + if (m_mouseDirH != 0.0f) + m_directionH -= m_mouseDirH * event.rTime * 0.7f * m_speed; + + m_terrain->ValidPosition(m_eyePt, 10.0f); + + if ( m_terrain->MoveOnFloor(m_eyePt, false) ) + { + m_eyePt.y += m_heightEye; + + Math::Vector pos = m_eyePt; + if ( m_terrain->MoveOnFloor(pos, false) ) + { + pos.y += 2.0f; + if ( m_eyePt.y < pos.y ) + m_eyePt.y = pos.y; + } + + } + + Math::Vector lookatPt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f); + + if (m_terrain->MoveOnFloor(lookatPt, true)) + lookatPt.y += m_heightLookat; + + SetViewTime(m_eyePt, lookatPt, event.rTime); + + return true; +} + +bool Gfx::CCamera::EventFrameOnBoard(const Event &event) +{ + if (m_cameraObj != NULL) + { + Math::Vector lookatPt, upVec; + m_cameraObj->SetViewFromHere(m_eyePt, m_directionH, m_directionV, + lookatPt, vUpVec, m_type); + Math::Vector eye = m_effectOffset * 0.3f + m_eyePt; + Math::Vector lookat = m_effectOffset * 0.3f + lookatPt; + + SetViewParams(eye, lookat, upVec); + m_actualEye = eye; + m_actualLookat = lookat; + } + return true; +} + +bool Gfx::CCamera::EventFrameInfo(const Event &event) +{ + SetViewTime(Math::Vector(0.0f, 0.0f, 0.0f), + Math::Vector(0.0f, 0.0f, 1.0f), + event.rTime); + return true; +} + +bool Gfx::CCamera::EventFrameVisit(const Event &event) +{ + m_visitTime += event.rTime; + + // +/-. + if (event.keyState & KS_NUMPLUS) + { + m_visitDist -= event.rTime * 50.0f * m_speed; + if (m_visitDist < 20.0f) m_visitDist = 20.0f; + } + if (event.keyState & KS_NUMMINUS) + { + m_visitDist += event.rTime * 50.0f * m_speed; + if (m_visitDist > 200.0f) m_visitDist = 200.0f; + } + + // PageUp/Down. + if (event.keyState & KS_PAGEUP) + { + m_visitDirectionV -= event.rTime * 1.0f * m_speed; + if (m_visitDirectionV < -Math::PI * 0.40f) m_visitDirectionV = -Math::PI * 0.40f; + } + if (event.keyState & KS_PAGEDOWN) + { + m_visitDirectionV += event.rTime * 1.0f * m_speed; + if (m_visitDirectionV > 0.0f ) m_visitDirectionV = 0.0f; + } + + if (m_cameraScroll) + { + m_visitDist -= m_mouseDirV * event.rTime * 30.0f * m_speed; + if (m_visitDist < 20.0f) m_visitDist = 20.0f; + if (m_visitDist > 200.0f) m_visitDist = 200.0f; + } + + float angleH = (m_visitTime / 10.0f) * (Math::PI * 2.0f); + float angleV = m_visitDirectionV; + Math::Vector eye = RotateView(m_visitGoal, angleH, angleV, m_visitDist); + eye = ExcludeTerrain(eye, m_visitGoal, angleH, angleV); + eye = ExcludeObject(eye, m_visitGoal, angleH, angleV); + SetViewTime(eye, m_visitGoal, event.rTime); + + return true; +} + +bool Gfx::CCamera::EventFrameScript(const Event &event) +{ + SetViewTime(m_scriptEye + m_effectOffset, + m_scriptLookat + m_effectOffset, event.rTime); + return true; +} + +void Gfx::CCamera::SetScriptEye(Math::Vector eye) +{ + m_scriptEye = eye; +} + +void Gfx::CCamera::SetScriptLookat(Math::Vector lookat) +{ + m_scriptLookat = lookat; +} + +void Gfx::CCamera::SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, + const Math::Vector &up) +{ + m_engine->SetViewParams(eye, lookat, up, m_eyeDistance); + + bool under = (eye.y < m_water->GetLevel()); // Is it underwater? + if (m_type == Gfx::CAM_TYPE_INFO) + under = false; + + m_engine->SetRankView(under ? 1 : 0); +} + +Math::Vector Gfx::CCamera::ExcludeTerrain(Math::Vector eye, Math::Vector lookat, + float &angleH, float &angleV) +{ + Math::Vector pos = eye; + if (m_terrain->MoveOnFloor(pos)) + { + float dist = Math::DistanceProjected(lookat, pos); + pos.y += 2.0f+dist*0.1f; + if ( pos.y > eye.y ) + { + angleV = -Math::RotateAngle(dist, pos.y-lookat.y); + eye = RotateView(lookat, angleH, angleV, dist); + } + } + return eye; +} + +Math::Vector Gfx::CCamera::ExcludeObject(Math::Vector eye, Math::Vector lookat, + float &angleH, float &angleV) +{ + return eye; + +// TODO: check the commented out code: +/* + for (int i = 0; i < 1000000; i++) + { + CObject* obj = static_cast<CObject*>( m_iMan->SearchInstance(CLASS_OBJECT, i) ); + if (obj == NULL) + break; + + int j = 0; + Math::Vector oPos; + float oRad; + while (obj->GetCrashSphere(j++, oPos, oRad)) + { + float dist = Math::Distance(oPos, eye); + if (dist < oRad + 2.0f) + eye.y = oPos.y + oRad + 2.0f; + } + } + + return eye;*/ +} diff --git a/src/graphics/engine/camera.h b/src/graphics/engine/camera.h new file mode 100644 index 0000000..935f8b0 --- /dev/null +++ b/src/graphics/engine/camera.h @@ -0,0 +1,386 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * 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/. + +// camera.h + +#pragma once + +#include "engine.h" +#include "common/event.h" + + +class CInstanceManager; +class CObject; + +namespace Gfx { + + +/** + \enum CameraType + \brief Type of camera */ +enum CameraType +{ + //! Undefined + CAM_TYPE_NULL = 0, + //! Free camera (? never in principle ?) + CAM_TYPE_FREE = 1, + //! Camera while editing a program + CAM_TYPE_EDIT = 2, + //! Camera on board a robot + CAM_TYPE_ONBOARD = 3, + //! Camera behind a robot + CAM_TYPE_BACK = 4, + //! Static camera following robot + CAM_TYPE_FIX = 5, + //! Camera steady after explosion + CAM_TYPE_EXPLO = 6, + //! Camera during a film script + CAM_TYPE_SCRIPT = 7, + //! Camera for displaying information + CAM_TYPE_INFO = 8, + //! Visit instead of an error + CAM_TYPE_VISIT = 9, + //! Camera for dialog + CAM_TYPE_DIALOG = 10, + //! Static camera height + CAM_TYPE_PLANE = 11, +}; + +enum CameraSmooth +{ + //! Sharp + CAM_SMOOTH_NONE = 0, + //! Normal + CAM_SMOOTH_NORM = 1, + //! Hard + CAM_SMOOTH_HARD = 2, + //! Special + CAM_SMOOTH_SPEC = 3, +}; + +enum CenteringPhase +{ + CAM_PHASE_NULL = 0, + CAM_PHASE_START = 1, + CAM_PHASE_WAIT = 2, + CAM_PHASE_STOP = 3, +}; + +enum CameraEffect +{ + //! No effect + CAM_EFFECT_NULL = 0, + //! Digging in + CAM_EFFECT_TERRAFORM = 1, + //! ? Vehicle driving is severely ? + CAM_EFFECT_CRASH = 2, + //! Explosion + CAM_EFFECT_EXPLO = 3, + //! ? Not mortal shot ? + CAM_EFFECT_SHOT = 4, + //! Vibration during construction + CAM_EFFECT_VIBRATION = 5, + //! ? Spleen reactor ? + CAM_EFFECT_PET = 6, +}; + +enum CameraOverEffect +{ + //! No effect + CAM_OVER_EFFECT_NULL = 0, + //! Flash red + CAM_OVER_EFFECT_BLOOD = 1, + //! White -> nothing + CAM_OVER_EFFECT_FADEIN_WHITE = 2, + //! Nothing -> white + CAM_OVER_EFFECT_FADEOUT_WHITE = 3, + //! Nothing -> blue + CAM_OVER_EFFECT_FADEOUT_BLACK = 4, + //! Lightning + CAM_OVER_EFFECT_LIGHTNING = 5, +}; + + +/** + \class CCamera + \brief Camera moving in 3D scene + + ... */ +class CCamera { + + public: + CCamera(CInstanceManager* iMan); + ~CCamera(); + + //! Management of an event + bool EventProcess(const Event &event); + + //! Initializes the camera + void Init(Math::Vector eye, Math::Vector lookat, float delay); + + //! Sets the object controlling the camera + void SetObject(CObject* object); + CObject* GetObject(); + + //! Change the type of camera + void SetType(Gfx::CameraType type); + Gfx::CameraType GetType(); + + //! Management of the smoothing mode + void SetSmooth(CameraSmooth type); + Gfx::CameraSmooth GetSmoth(); + + //! Management of the setback distance + void SetDist(float dist); + float GetDist(); + + //! Manage angle mode Gfx::CAM_TYPE_FIX + void SetFixDirection(float angle); + float GetFixDirection(); + + //! Managing the triggering mode of the camera panning + void SetRemotePan(float value); + float GetRemotePan(); + + //! Management of the remote zoom (0 .. 1) of the camera + void SetRemoteZoom(float value); + float GetRemoteZoom(); + + //! Start with a tour round the camera + void StartVisit(Math::Vector goal, float dist); + //! Circular end of a visit with the camera + void StopVisit(); + + //! Returns the point of view of the camera + void GetCamera(Math::Vector &eye, Math::Vector &lookat); + + //! Specifies a special movement of camera to frame action + bool StartCentering(CObject *object, float angleH, float angleV, float dist, float time); + //! Ends a special movement of camera to frame action + bool StopCentering(CObject *object, float time); + //! Stop framing special in the current position + void AbortCentering(); + + //! Removes the special effect with the camera + void FlushEffect(); + //! Starts a special effect with the camera + void StartEffect(Gfx::CameraEffect effect, Math::Vector pos, float force); + + //! Removes the effect of superposition in the foreground + void FlushOver(); + //! Specifies the base color + void SetOverBaseColor(Gfx::Color color); + void StartOver(Gfx::CameraOverEffect effect, Math::Vector pos, float force); + + //! Sets the soft movement of the camera + void FixCamera(); + void SetScriptEye(Math::Vector eye); + void SetScriptLookat(Math::Vector lookat); + + void SetEffect(bool enable); + void SetCameraScroll(bool scroll); + void SetCameraInvertX(bool invert); + void SetCameraInvertY(bool invert); + + //! Returns an additional force to turn + float GetMotorTurn(); + //! Returns the default sprite to use for the mouse + Gfx::EngineMouseType GetMouseDef(Math::Point pos); + +protected: + //! Changes the camera according to the mouse moved + bool EventMouseMove(const Event &event); + //! Mouse wheel operation + void EventMouseWheel(int dir); + //! Changes the camera according to the time elapsed + bool EventFrame(const Event &event); + //! Moves the point of view + bool EventFrameFree(const Event &event); + //! Moves the point of view + bool EventFrameEdit(const Event &event); + //! Moves the point of view + bool EventFrameDialog(const Event &event); + //! Moves the point of view + bool EventFrameBack(const Event &event); + //! Moves the point of view + bool EventFrameFix(const Event &event); + //! Moves the point of view + bool EventFrameExplo(const Event &event); + //! Moves the point of view + bool EventFrameOnBoard(const Event &event); + //! Moves the point of view + bool EventFrameInfo(const Event &event); + //! Moves the point of view + bool EventFrameVisit(const Event &event); + //! Moves the point of view + bool EventFrameScript(const Event &event); + + //! Specifies the location and direction of view to the 3D engine + void SetViewTime(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, float rTime); + //! Avoid the obstacles + bool IsCollision(Math::Vector &eye, Math::Vector lookat); + //! Avoid the obstacles + bool IsCollisionBack(Math::Vector &eye, Math::Vector lookat); + //! Avoid the obstacles + bool IsCollisionFix(Math::Vector &eye, Math::Vector lookat); + + //! Adjusts the camera not to enter the ground + Math::Vector ExcludeTerrain(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV); + //! Adjusts the camera not to enter an object + Math::Vector ExcludeObject(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV); + + //! Specifies the location and direction of view + void SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, const Math::Vector &up); + //! Advances the effect of the camera + void EffectFrame(const Event &event); + //! Advanced overlay effect in the foreground + void OverFrame(const Event &event); + +protected: + CInstanceManager* m_iMan; + Gfx::CEngine* m_engine; + Gfx::CTerrain* m_terrain; + Gfx::CWater* m_water; + + //! The type of camera + Gfx::CameraType m_type; + //! Type of smoothing + Gfx::CameraSmooth m_smooth; + //! Object linked to the camera + CObject* m_cameraObj; + + //! Distance between the eyes + float m_eyeDistance; + //! Time of initial centering + float m_initDelay; + + //! Current eye + Math::Vector m_actualEye; + //! Current aim + Math::Vector m_actualLookat; + //! Final eye + Math::Vector m_finalEye; + //! Final aim + Math::Vector m_finalLookat; + //! Normal eye + Math::Vector m_normEye; + //! Normal aim + Math::Vector m_normLookat; + + float m_focus; + + bool m_rightDown; + Math::Point m_rightPosInit; + Math::Point m_rightPosCenter; + Math::Point m_rightPosMove; + + //! CAM_TYPE_FREE: eye + Math::Vector m_eyePt; + //! CAM_TYPE_FREE: horizontal direction + float m_directionH; + //! CAM_TYPE_FREE: vertical direction + float m_directionV; + //! CAM_TYPE_FREE: height above the ground + float m_heightEye; + //! CAM_TYPE_FREE: height above the ground + float m_heightLookat; + //! CAM_TYPE_FREE: speed of movement + float m_speed; + + //! CAM_TYPE_BACK: distance + float m_backDist; + //! CAM_TYPE_BACK: distance minimal + float m_backMin; + //! CAM_TYPE_BACK: additional direction + float m_addDirectionH; + //! CAM_TYPE_BACK: additional direction + float m_addDirectionV; + bool m_transparency; + + //! CAM_TYPE_FIX: distance + float m_fixDist; + //! CAM_TYPE_FIX: direction + float m_fixDirectionH; + //! CAM_TYPE_FIX: direction + float m_fixDirectionV; + + //! CAM_TYPE_VISIT: target position + Math::Vector m_visitGoal; + //! CAM_TYPE_VISIT: distance + float m_visitDist; + //! CAM_TYPE_VISIT: relative time + float m_visitTime; + //! CAM_TYPE_VISIT: initial type + Gfx::CameraType m_visitType; + //! CAM_TYPE_VISIT: direction + float m_visitDirectionH; + //! CAM_TYPE_VISIT: direction + float m_visitDirectionV; + + //! CAM_TYPE_EDIT: height + float m_editHeight; + + float m_remotePan; + float m_remoteZoom; + + Math::Point m_mousePos; + float m_mouseDirH; + float m_mouseDirV; + float m_mouseMarging; + + float m_motorTurn; + + Gfx::CenteringPhase m_centeringPhase; + float m_centeringAngleH; + float m_centeringAngleV; + float m_centeringDist; + float m_centeringCurrentH; + float m_centeringCurrentV; + float m_centeringTime; + float m_centeringProgress; + + CameraEffect m_effectType; + Math::Vector m_effectPos; + float m_effectForce; + float m_effectProgress; + Math::Vector m_effectOffset; + + OverEffect m_overType; + float m_overForce; + float m_overTime; + Gfx::Color m_overColorBase; + Gfx::Color m_overColor; + int m_overMode; + float m_overFadeIn; + float m_overFadeOut; + + Math::Vector m_scriptEye; + Math::Vector m_scriptLookat; + + //! Shocks if explosion? + bool m_effect; + //! Scroll in the edges? + bool m_cameraScroll; + //! X inversion in the edges? + bool m_cameraInvertX; + //! Y inversion in the edges? + bool m_cameraInvertY; + +}; + + +}; // namespace Gfx diff --git a/src/graphics/common/cloud.cpp b/src/graphics/engine/cloud.cpp index 707f641..d0e5ed8 100644 --- a/src/graphics/common/cloud.cpp +++ b/src/graphics/engine/cloud.cpp @@ -17,7 +17,7 @@ // cloud.cpp -#include "graphics/common/cloud.h" +#include "graphics/engine/cloud.h" // TODO implementation diff --git a/src/graphics/common/cloud.h b/src/graphics/engine/cloud.h index 19b689f..d2d29d7 100644 --- a/src/graphics/common/cloud.h +++ b/src/graphics/engine/cloud.h @@ -20,7 +20,7 @@ #pragma once #include "common/event.h" -#include "graphics/common/color.h" +#include "graphics/core/color.h" #include "math/point.h" #include "math/vector.h" diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp new file mode 100644 index 0000000..e544ee3 --- /dev/null +++ b/src/graphics/engine/engine.cpp @@ -0,0 +1,743 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * 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/. + +// engine.cpp + +#include "graphics/engine/engine.h" + +#include "app/app.h" +#include "common/iman.h" +#include "common/image.h" +#include "common/key.h" +#include "common/logger.h" +#include "graphics/core/device.h" +#include "math/geometry.h" + +// Initial size of various vectors +const int OBJECT_PREALLOCATE_COUNT = 1200; +const int SHADOW_PREALLOCATE_COUNT = 500; +const int GROUNDSPOT_PREALLOCATE_COUNT = 100; + +const int LEVEL1_PREALLOCATE_COUNT = 50; +const int LEVEL2_PREALLOCATE_COUNT = 100; +const int LEVEL3_PREALLOCATE_COUNT = 5; +const int LEVEL4_PREALLOCATE_COUNT = 10; +const int LEVEL5_PREALLOCATE_COUNT = 100; +const int LEVEL5_VERTEX_PREALLOCATE_COUNT = 200; + + +Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app) +{ + m_iMan = iMan; + m_app = app; + m_device = NULL; + + m_wasInit = false; + + m_iMan = iMan; + m_iMan->AddInstance(CLASS_ENGINE, this); + m_app = app; + + m_lightMan = NULL; + m_text = NULL; + m_particle = NULL; + m_water = NULL; + m_cloud = NULL; + m_lightning = NULL; + m_planet = NULL; + m_sound = NULL; + m_terrain = NULL; + + m_focus = 0.75f; + m_baseTime = 0; + m_lastTime = 0; + m_absTime = 0.0f; + m_rankView = 0; + + m_ambientColor[0] = Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f); + m_ambientColor[1] = Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f); + m_fogColor[0] = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f); + m_fogColor[1] = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f); + m_deepView[0] = 1000.0f; + m_deepView[1] = 1000.0f; + m_fogStart[0] = 0.75f; + m_fogStart[1] = 0.75f; + m_waterAddColor = Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f); + + m_pause = false; + m_render = true; + m_movieLock = false; + m_shadowVisible = true; + m_groundSpotVisible = true; + m_dirty = true; + m_fog = true; + m_speed = 1.0f; + m_secondTexNum = 0; + m_eyeDirH = 0.0f; + m_eyeDirV = 0.0f; + m_backgroundName = ""; // no background image + m_backgroundColorUp = 0; + m_backgroundColorDown = 0; + m_backgroundCloudUp = 0; + m_backgroundCloudDown = 0; + m_backgroundFull = false; + m_backgroundQuarter = false; + m_overFront = true; + m_overColor = 0; + m_overMode = ENG_RSTATE_TCOLOR_BLACK; + m_frontsizeName = ""; // no front image + m_hiliteRank[0] = -1; // empty list + m_eyePt = Math::Vector(0.0f, 0.0f, 0.0f); + m_lookatPt = Math::Vector(0.0f, 0.0f, 1.0f); + m_drawWorld = true; + m_drawFront = false; + m_limitLOD[0] = 100.0f; + m_limitLOD[1] = 200.0f; + m_particuleDensity = 1.0f; + m_clippingDistance = 1.0f; + m_lastClippingDistance = m_clippingDistance; + m_objectDetail = 1.0f; + m_lastObjectDetail = m_objectDetail; + m_terrainVision = 1000.0f; + m_gadgetQuantity = 1.0f; + m_textureQuality = 1; + m_totoMode = true; + m_lensMode = true; + m_waterMode = true; + m_skyMode = true; + m_backForce = true; + m_planetMode = true; + m_lightMode = true; + m_editIndentMode = true; + m_editIndentValue = 4; + m_tracePrecision = 1.0f; + + m_alphaMode = 1; + + m_forceStateColor = true; + m_stateColor = false; + + m_blackSrcBlend[0] = 0; + m_blackDestBlend[0] = 0; + m_whiteSrcBlend[0] = 0; + m_whiteDestBlend[0] = 0; + m_diffuseSrcBlend[0] = 0; + m_diffuseDestBlend[0] = 0; + m_alphaSrcBlend[0] = 0; + m_alphaDestBlend[0] = 0; + + m_updateGeometry = false; + + m_mice[Gfx::ENG_MOUSE_NORM] = Gfx::EngineMouse( 0, 1, 32, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point( 1.0f, 1.0f)); + m_mice[Gfx::ENG_MOUSE_WAIT] = Gfx::EngineMouse( 2, 3, 33, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point( 8.0f, 12.0f)); + m_mice[Gfx::ENG_MOUSE_HAND] = Gfx::EngineMouse( 4, 5, 34, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point( 7.0f, 2.0f)); + m_mice[Gfx::ENG_MOUSE_NO] = Gfx::EngineMouse( 6, 7, 35, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point(10.0f, 10.0f)); + m_mice[Gfx::ENG_MOUSE_EDIT] = Gfx::EngineMouse( 8, 9, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 6.0f, 10.0f)); + m_mice[Gfx::ENG_MOUSE_CROSS] = Gfx::EngineMouse(10, 11, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(10.0f, 10.0f)); + m_mice[Gfx::ENG_MOUSE_MOVEV] = Gfx::EngineMouse(12, 13, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 5.0f, 11.0f)); + m_mice[Gfx::ENG_MOUSE_MOVEH] = Gfx::EngineMouse(14, 15, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(11.0f, 5.0f)); + m_mice[Gfx::ENG_MOUSE_MOVED] = Gfx::EngineMouse(16, 17, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 9.0f)); + m_mice[Gfx::ENG_MOUSE_MOVEI] = Gfx::EngineMouse(18, 19, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 9.0f)); + m_mice[Gfx::ENG_MOUSE_MOVE] = Gfx::EngineMouse(20, 21, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(11.0f, 11.0f)); + m_mice[Gfx::ENG_MOUSE_TARGET] = Gfx::EngineMouse(22, 23, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(15.0f, 15.0f)); + m_mice[Gfx::ENG_MOUSE_SCROLLL] = Gfx::EngineMouse(24, 25, 43, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 2.0f, 9.0f)); + m_mice[Gfx::ENG_MOUSE_SCROLLR] = Gfx::EngineMouse(26, 27, 44, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(17.0f, 9.0f)); + m_mice[Gfx::ENG_MOUSE_SCROLLU] = Gfx::EngineMouse(28, 29, 45, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 2.0f)); + m_mice[Gfx::ENG_MOUSE_SCROLLD] = Gfx::EngineMouse(30, 31, 46, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 17.0f)); + + m_mouseSize = Math::Point(0.04f, 0.04f * (800.0f / 600.0f)); + m_mousePos = Math::Point(0.5f, 0.5f); + m_mouseType = Gfx::ENG_MOUSE_NORM; + m_mouseVisible = false; + + m_texPath = "textures/"; + m_defaultTexParams.format = Gfx::TEX_IMG_RGBA; + m_defaultTexParams.mipmap = true; + m_defaultTexParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR; + m_defaultTexParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR; + + m_objectTree.reserve(LEVEL1_PREALLOCATE_COUNT); + m_objects.reserve(OBJECT_PREALLOCATE_COUNT); + m_shadow.reserve(SHADOW_PREALLOCATE_COUNT); + m_groundSpot.reserve(GROUNDSPOT_PREALLOCATE_COUNT); +} + +Gfx::CEngine::~CEngine() +{ + m_iMan = NULL; + m_app = NULL; + m_device = NULL; + + m_sound = NULL; + m_terrain = NULL; +} + +bool Gfx::CEngine::GetWasInit() +{ + return m_wasInit; +} + +std::string Gfx::CEngine::GetError() +{ + return m_error; +} + +bool Gfx::CEngine::Create() +{ + m_wasInit = true; + + /*m_lightMan = new Gfx::CLight(m_iMan, this); + m_text = new Gfx::CText(m_iMan, this); + m_particle = new Gfx::CParticle(m_iMan, this); + m_water = new Gfx::CWater(m_iMan, this); + m_cloud = new Gfx::CCloud(m_iMan, this); + m_lightning = new Gfx::CLightning(m_iMan, this); + m_planet = new Gfx::CPlanet(m_iMan, this);*/ + + m_matWorldInterface.LoadIdentity(); + m_matViewInterface.LoadIdentity(); + Math::LoadOrthoProjectionMatrix(m_matProjInterface, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f); + + return true; +} + +void Gfx::CEngine::Destroy() +{ + // TODO + + /*delete m_lightMan; + m_lightMan = NULL; + + delete m_text; + m_text = NULL; + + delete m_particle; + m_particle = NULL; + + delete m_water; + m_water = NULL; + + delete m_cloud; + m_cloud = NULL; + + delete m_lightning; + m_lightning = NULL; + + delete m_planet; + m_planet = NULL;*/ + + m_wasInit = false; +} + +void Gfx::CEngine::SetDevice(Gfx::CDevice *device) +{ + m_device = device; +} + +Gfx::CDevice* Gfx::CEngine::GetDevice() +{ + return m_device; +} + +bool Gfx::CEngine::AfterDeviceSetInit() +{ + m_device->SetClearColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)); + + m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, false); + + Gfx::TextureCreateParams params; + params.format = Gfx::TEX_IMG_RGB; + params.minFilter = Gfx::TEX_MIN_FILTER_NEAREST; + params.magFilter = Gfx::TEX_MAG_FILTER_NEAREST; + params.mipmap = false; + m_miceTexture = CreateTexture("mouse.png", params); + + return true; +} + +void Gfx::CEngine::ResetAfterDeviceChanged() +{ + // TODO +} + + +Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName, const Gfx::TextureCreateParams ¶ms) +{ + CImage img; + if (! img.Load(m_app->GetDataFilePath(m_texPath, texName))) + { + std::stringstream str; + str << "Couldn't load texture '" << texName << "': " << img.GetError(); + m_error = str.str(); + return Gfx::Texture(); // invalid texture + } + + Gfx::Texture result = m_device->CreateTexture(&img, params); + + if (! result.valid) + { + std::stringstream str; + str << "Couldn't load texture '" << texName << "': " << m_device->GetError(); + m_error = str.str(); + return result; + } + + m_texNameMap[texName] = result; + m_revTexNameMap[result] = texName; + + return result; +} + +Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName) +{ + return CreateTexture(texName, m_defaultTexParams); +} + +void Gfx::CEngine::DestroyTexture(const std::string &texName) +{ + std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(texName); + if (it == m_texNameMap.end()) + return; + + std::map<Gfx::Texture, std::string>::iterator revIt = m_revTexNameMap.find((*it).second); + + m_device->DestroyTexture((*it).second); + + m_revTexNameMap.erase(revIt); + m_texNameMap.erase(it); +} + +void Gfx::CEngine::SetTexture(const std::string &name, int stage) +{ + std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(name); + if (it != m_texNameMap.end()) + m_device->SetTexture(stage, (*it).second); + + // TODO if not present... +} + +void Gfx::CEngine::SetMaterial(const Gfx::Material &mat) +{ + m_device->SetMaterial(mat); +} + +void Gfx::CEngine::SetState(int state, Gfx::Color color) +{ + if ( state == m_lastState && color == m_lastColor ) + return; + + m_lastState = state; + m_lastColor = color; + + if ( m_alphaMode != 1 && (state & Gfx::ENG_RSTATE_ALPHA) ) + { + state &= ~Gfx::ENG_RSTATE_ALPHA; + + if (m_alphaMode == 2) + state |= Gfx::ENG_RSTATE_TTEXTURE_BLACK; + } + + // TODO other modes & thorough testing + + if (state & Gfx::ENG_RSTATE_TTEXTURE_BLACK) // The transparent black texture? + { + m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false); + m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false); + m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true); + m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false); + m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true); + + m_device->SetBlendFunc(Gfx::BLEND_ONE, Gfx::BLEND_INV_SRC_COLOR); + m_device->SetTextureEnabled(0, true); + m_device->SetTextureFactor(color); + + Gfx::TextureStageParams params; + params.colorOperation = Gfx::TEX_MIX_OPER_MODULATE; + params.colorArg1 = Gfx::TEX_MIX_ARG_TEXTURE; + params.colorArg2 = Gfx::TEX_MIX_ARG_FACTOR; + params.alphaOperation = Gfx::TEX_MIX_OPER_MODULATE; + m_device->SetTextureStageParams(0, params); + } + else if (state & Gfx::ENG_RSTATE_TTEXTURE_WHITE) // The transparent white texture? + { + m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false); + m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false); + m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true); + m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false); + m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true); + + m_device->SetBlendFunc(Gfx::BLEND_DST_COLOR, Gfx::BLEND_ZERO); + m_device->SetTextureEnabled(0, true); + m_device->SetTextureFactor(color.Inverse()); + + Gfx::TextureStageParams params; + params.colorOperation = Gfx::TEX_MIX_OPER_ADD; + params.colorArg1 = Gfx::TEX_MIX_ARG_TEXTURE; + params.colorArg2 = Gfx::TEX_MIX_ARG_FACTOR; + params.alphaOperation = Gfx::TEX_MIX_OPER_MODULATE; + m_device->SetTextureStageParams(0, params); + } + else if (state & Gfx::ENG_RSTATE_TCOLOR_BLACK) // The transparent black color? + { + m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false); + m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false); + m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true); + m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false); + m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true); + + m_device->SetBlendFunc(Gfx::BLEND_ONE, Gfx::BLEND_INV_SRC_COLOR); + + m_device->SetTextureFactor(color); + m_device->SetTextureEnabled(0, true); + m_device->SetTextureStageParams(0, Gfx::TextureStageParams()); + } + else if (state & Gfx::ENG_RSTATE_TCOLOR_WHITE) // The transparent white color? + { + m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false); + m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false); + m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true); + m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false); + m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true); + + m_device->SetBlendFunc(Gfx::BLEND_DST_COLOR, Gfx::BLEND_ZERO); + + m_device->SetTextureFactor(color.Inverse()); + m_device->SetTextureEnabled(0, true); + m_device->SetTextureStageParams(0, Gfx::TextureStageParams()); + } + else if (state & Gfx::ENG_RSTATE_TDIFFUSE) // diffuse color as transparent? + { + /*m_device->SetRenderState(D3DRENDERSTATE_FOGENABLE, false); + m_device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); + m_device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, true); + m_device->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, false); + m_device->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_diffuseSrcBlend[1]); + m_device->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_diffuseDestBlend[1]); + + m_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + m_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + m_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);*/ + } + else if (state & Gfx::ENG_RSTATE_ALPHA) // image with alpha channel? + { + /*m_device->SetRenderState(D3DRENDERSTATE_FOGENABLE, true); + m_device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, true); + m_device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, false); + m_device->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, true); + m_device->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATER); + m_device->SetRenderState(D3DRENDERSTATE_ALPHAREF, (DWORD)(128)); + m_device->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_alphaSrcBlend[1]); + m_device->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_alphaSrcBlend[1]); + + m_device->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, color); + m_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + m_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + m_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + m_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + m_device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);*/ + } + else // normal ? + { + m_device->SetRenderState(Gfx::RENDER_STATE_FOG, true); + m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, true); + m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, false); + m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false); + m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true); + + m_device->SetTextureEnabled(0, true); + m_device->SetTextureStageParams(0, Gfx::TextureStageParams()); + + /*m_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + m_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + m_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + m_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);*/ + } + + if (state & Gfx::ENG_RSTATE_FOG) + m_device->SetRenderState(Gfx::RENDER_STATE_FOG, true); + + + bool second = m_groundSpotVisible || m_dirty; + + if ( !m_groundSpotVisible && (state & Gfx::ENG_RSTATE_SECOND) != 0 ) second = false; + if ( !m_dirty && (state & Gfx::ENG_RSTATE_SECOND) == 0 ) second = false; + + if ( (state & ENG_RSTATE_DUAL_BLACK) && second ) + { + /*m_device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); + m_device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); + m_device->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); + m_device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + m_device->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);*/ + } + else if ( (state & ENG_RSTATE_DUAL_WHITE) && second ) + { + /*m_device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADD); + m_device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); + m_device->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); + m_device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + m_device->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);*/ + } + else + { + m_device->SetTextureEnabled(1, false); + } + + if (state & Gfx::ENG_RSTATE_WRAP) + { + /*m_device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + m_device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);*/ + } + else if (state & Gfx::ENG_RSTATE_CLAMP) + { + /*m_device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + m_device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);*/ + } + else + { + /*m_device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + m_device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);*/ + } + + if (state & Gfx::ENG_RSTATE_2FACE) + { + m_device->SetRenderState(Gfx::RENDER_STATE_CULLING, false); + } + else + { + m_device->SetRenderState(Gfx::RENDER_STATE_CULLING, true); + m_device->SetCullMode(Gfx::CULL_CCW); + } + + if (state & Gfx::ENG_RSTATE_LIGHT) + m_device->SetGlobalAmbient(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)); + else + m_device->SetGlobalAmbient(m_ambientColor[m_rankView]); +} + +bool Gfx::CEngine::ProcessEvent(const Event &event) +{ + if (event.type == EVENT_MOUSE_MOVE) + { + m_mousePos = event.mouseMove.pos; + } + else if (event.type == EVENT_KEY_DOWN) + { + // !! Debug, to be removed later !! + + if (event.key.key == KEY(F1)) + { + m_mouseVisible = !m_mouseVisible; + m_app->SetSystemMouseVisible(! m_app->GetSystemMouseVisibile()); + } + else if (event.key.key == KEY(F2)) + { + int index = static_cast<int>(m_mouseType); + m_mouseType = static_cast<Gfx::EngineMouseType>( (index + 1) % Gfx::ENG_MOUSE_COUNT ); + } + } + + // By default, pass on all events + return true; +} + +bool Gfx::CEngine::Render() +{ + m_statisticTriangle = 0; + + m_lastState = -1; + SetState(Gfx::ENG_RSTATE_NORMAL); + + m_device->BeginScene(); + + SetUp3DView(); + + if (! Draw3DScene() ) + return false; + + SetUpInterfaceView(); + + if (! DrawInterface() ) + return false; + + m_device->EndScene(); + + return true; +} + +void Gfx::CEngine::SetUp3DView() +{ + // TODO +} + +bool Gfx::CEngine::Draw3DScene() +{ + // TODO + return true; +} + +void Gfx::CEngine::SetUpInterfaceView() +{ + m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface); + m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface); + m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProjInterface); +} + +bool Gfx::CEngine::DrawInterface() +{ + Gfx::VertexCol vertices[3] = + { + Gfx::VertexCol(Math::Vector( 0.25f, 0.25f, 0.0f), Gfx::Color(1.0f, 0.0f, 0.0f)), + Gfx::VertexCol(Math::Vector( 0.75f, 0.25f, 0.0f), Gfx::Color(0.0f, 1.0f, 0.0f)), + Gfx::VertexCol(Math::Vector( 0.5f, 0.75f, 0.0f), Gfx::Color(0.0f, 0.0f, 1.0f)) + }; + + m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, vertices, 3); + + DrawMouse(); + + return true; +} + +void Gfx::CEngine::DrawMouse() +{ + if (! m_mouseVisible) + return; + + if (m_app->GetSystemMouseVisibile()) + return; + + Gfx::Material material; + material.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f); + material.ambient = Gfx::Color(0.5f, 0.5f, 0.5f); + + m_device->SetMaterial(material); + m_device->SetTexture(0, m_miceTexture); + + int index = static_cast<int>(m_mouseType); + + Math::Point pos = m_mousePos; + pos.x = m_mousePos.x - (m_mice[index].hotPoint.x * m_mouseSize.x) / 32.0f; + pos.y = m_mousePos.y - ((32.0f - m_mice[index].hotPoint.y) * m_mouseSize.y) / 32.0f; + + Math::Point shadowPos; + shadowPos.x = pos.x + (4.0f/800.0f); + shadowPos.y = pos.y - (3.0f/600.0f); + + SetState(Gfx::ENG_RSTATE_TCOLOR_WHITE); + DrawMouseSprite(shadowPos, m_mouseSize, m_mice[index].iconShadow); + + SetState(m_mice[index].mode1); + DrawMouseSprite(pos, m_mouseSize, m_mice[index].icon1); + + SetState(m_mice[index].mode2); + DrawMouseSprite(pos, m_mouseSize, m_mice[index].icon2); +} + +void Gfx::CEngine::DrawMouseSprite(Math::Point pos, Math::Point size, int icon) +{ + if (icon == -1) + return; + + Math::Point p1 = pos; + Math::Point p2 = p1 + size; + + float u1 = (32.0f / 256.0f) * (icon % 8); + float v1 = (32.0f / 256.0f) * (icon / 8); + float u2 = u1 + (32.0f / 256.0f); + float v2 = v1 + (32.0f / 256.0f); + + float dp = 0.5f / 256.0f; + u1 += dp; + v1 += dp; + u2 -= dp; + v2 -= dp; + + Math::Vector normal(0.0f, 0.0f, -1.0f); + + Gfx::Vertex vertex[4] = + { + Gfx::Vertex(Math::Vector(p1.x, p1.y, 0.0f), normal, Math::Point(u1, v2)), + Gfx::Vertex(Math::Vector(p2.x, p1.y, 0.0f), normal, Math::Point(u2, v2)), + Gfx::Vertex(Math::Vector(p1.x, p2.y, 0.0f), normal, Math::Point(u1, v1)), + Gfx::Vertex(Math::Vector(p2.x, p2.y, 0.0f), normal, Math::Point(u2, v1)) + }; + + m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4); + AddStatisticTriangle(2); +} + +bool Gfx::CEngine::GetPause() +{ + return m_pause; +} + +Math::Vector Gfx::CEngine::GetLookatPt() +{ + return m_lookatPt; +} + +Math::Vector Gfx::CEngine::GetEyePt() +{ + return m_eyePt; +} + +void Gfx::CEngine::SetMouseVisible(bool visible) +{ + m_mouseVisible = visible; +} + +bool Gfx::CEngine::GetMouseVisible() +{ + return m_mouseVisible; +} + +void Gfx::CEngine::SetMousePos(Math::Point pos) +{ + m_mousePos = pos; +} + +Math::Point Gfx::CEngine::GetMousePos() +{ + return m_mousePos; +} + +void Gfx::CEngine::SetMouseType(Gfx::EngineMouseType type) +{ + m_mouseType = type; +} + +Gfx::EngineMouseType Gfx::CEngine::GetMouseType() +{ + return m_mouseType; +} + +void Gfx::CEngine::AddStatisticTriangle(int count) +{ + m_statisticTriangle += count; +} + +void Gfx::CEngine::SetShowStat(bool show) +{ + m_showStats = show; +} + +bool Gfx::CEngine::GetShowStat() +{ + return m_showStats; +} + diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h new file mode 100644 index 0000000..25c5e5d --- /dev/null +++ b/src/graphics/engine/engine.h @@ -0,0 +1,1002 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * 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/. + +// engine.h + +#pragma once + + +#include "common/event.h" +#include "graphics/core/color.h" +#include "graphics/core/material.h" +#include "graphics/core/texture.h" +#include "graphics/core/vertex.h" +#include "math/intpoint.h" +#include "math/intsize.h" +#include "math/matrix.h" +#include "math/point.h" +#include "math/vector.h" + + +#include <string> +#include <vector> +#include <map> + + +class CApplication; +class CInstanceManager; +class CObject; +class CSound; + + +namespace Gfx { + +class CDevice; +class CLightManager; +class CText; +class CParticle; +class CWater; +class CCloud; +class CLightning; +class CPlanet; +class CTerrain; + + +/** + \enum EngineTriangleType + \brief Type of triangles drawn for engine objects */ +enum EngineTriangleType +{ + //! Triangles + ENG_TRIANGLE_TYPE_6T = 1, + //! Surfaces + ENG_TRIANGLE_TYPE_6S = 2 +}; + +/** + \struct EngineTriangle + \brief A triangle drawn by the graphics engine */ +struct EngineTriangle +{ + //! Triangle vertices + Gfx::VertexTex2 triangle[3]; + //! Material + Gfx::Material material; + //! Render state (TODO: ?) + int state; + //! 1st texture + Gfx::Texture tex1; + //! 2nd texture + Gfx::Texture tex2; + + EngineTriangle() + { + state = 0; + } +}; + +/** + \enum EngineObjectType + \brief Class of graphics engine object */ +enum EngineObjectType +{ + //! Object doesn't exist + ENG_OBJTYPE_NULL = 0, + //! Terrain + ENG_OBJTYPE_TERRAIN = 1, + //! Fixed object + ENG_OBJTYPE_FIX = 2, + //! Moving object + ENG_OBJTYPE_VEHICULE = 3, + //! Part of a moving object + ENG_OBJTYPE_DESCENDANT = 4, + //! Fixed object type quartz + ENG_OBJTYPE_QUARTZ = 5, + //! Fixed object type metal + ENG_OBJTYPE_METAL = 6 +}; + +/** + \struct EngineObject + \brief Object drawn by the graphics engine */ +struct EngineObject +{ + //! If true, the object is drawn + bool visible; + //! If true, object is behind the 2D interface + bool drawWorld; + //! If true, the shape is before the 2D interface + bool drawFront; + //! Number of triangles + int totalTriangles; + //! Type of object + Gfx::EngineObjectType type; + //! Transformation matrix + Math::Matrix transform; + //! Distance view - origin (TODO: ?) + float distance; + //! Bounding box min (origin 0,0,0 always included) + Math::Vector bboxMin; + //! bounding box max (origin 0,0,0 always included) + Math::Vector bboxMax; + //! Radius of the sphere at the origin + float radius; + //! Rank of the associated shadow + int shadowRank; + //! Transparency of the object [0, 1] + float transparency; + + EngineObject() + { + visible = false; + drawWorld = false; + drawFront = false; + totalTriangles = 0; + distance = 0.0f; + radius = 0.0f; + shadowRank = 0; + transparency = 0.0f; + } +}; + +struct EngineObjLevel1; +struct EngineObjLevel2; +struct EngineObjLevel3; +struct EngineObjLevel4; +struct EngineObjLevel5; + +/** + \struct EngineObjLevel5 + \brief Tier 5 of object tree */ +struct EngineObjLevel5 +{ + Gfx::Material material; + int state; + Gfx::EngineTriangleType type; + std::vector<Gfx::VertexTex2> vertices; + + EngineObjLevel5(); +}; + +/** + \struct EngineObjLevel4 + \brief Tier 4 of object tree */ +struct EngineObjLevel4 +{ + int reserved; + std::vector<Gfx::EngineObjLevel5> up; + Gfx::EngineObjLevel3* down; + + EngineObjLevel4(); +}; + +/** + \struct EngineObjLevel3 + \brief Tier 3 of object tree */ +struct EngineObjLevel3 +{ + float min; + float max; + std::vector<Gfx::EngineObjLevel4> up; + Gfx::EngineObjLevel2* down; + + EngineObjLevel3(); +}; + +/** + \struct EngineObjLevel2 + \brief Tier 2 of object tree */ +struct EngineObjLevel2 +{ + int objRank; + std::vector<Gfx::EngineObjLevel3> up; + Gfx::EngineObjLevel1* down; + + EngineObjLevel2(); +}; + +/** + \struct EngineObjLevel1 + \brief Tier 1 of object tree */ +struct EngineObjLevel1 +{ + Gfx::Texture tex1; + Gfx::Texture tex2; + std::vector<Gfx::EngineObjLevel2> up; + + EngineObjLevel1(); +}; + +/** + \struct EngineShadowType + \brief Type of shadow drawn by the graphics engine */ +enum EngineShadowType +{ + //! Normal shadow + ENG_SHADOW_NORM = 0, + //! TODO: ? + ENG_SHADOW_WORM = 1 +}; + +/** + \struct EngineShadow + \brief Shadow drawn by the graphics engine */ +struct EngineShadow +{ + //! If true, shadow is invisible (object being carried for example) + bool hide; + //! Rank of the associated object + int objRank; + //! Type of shadow + Gfx::EngineShadowType type; + //! Position of the shadow + Math::Vector pos; + //! Normal to the terrain + Math::Vector normal; + //! Angle of the shadow + float angle; + //! Radius of the shadow + float radius; + //! Intensity of the shadow + float intensity; + //! Height from the ground + float height; + + EngineShadow() + { + hide = false; + objRank = 0; + angle = radius = intensity = height = 0.0f; + } +}; + +/** + \struct EngineGroundSpot + \brief A spot (large shadow) drawn on the ground by the graphics engine */ +struct EngineGroundSpot +{ + //! Color of the shadow + Gfx::Color color; + //! Min altitude + float min; + //! Max altitude + float max; + //! Transition area + float smooth; + //! Position for the shadow + Math::Vector pos; + //! Radius of the shadow + float radius; + //! Position of the shadow drawn + Math::Vector drawPos; + //! Radius of the shadow drawn + float drawRadius; + + EngineGroundSpot() + { + min = max = smooth = radius = drawRadius = 0.0f; + } +}; + +/** + \enum EngineGroundMarkPhase + \brief Phase of life of an EngineGroundMark */ +enum EngineGroundMarkPhase +{ + //! Increase + ENG_GR_MARK_PHASE_INC = 1, + //! Fixed + ENG_GR_MARK_PHASE_FIX = 2, + //! Decrease + ENG_GR_MARK_PHASE_DEC = 2 +}; + +/** + \struct EngineGroundMark + \brief A mark on ground drawn by the graphics engine */ +struct EngineGroundMark +{ + //! If true, draw mark + bool draw; + //! Phase of life + Gfx::EngineGroundMarkPhase phase; + //! Times for 3 life phases + float delay[3]; + //! Fixed time + float fix; + //! Position for marks + Math::Vector pos; + //! Radius of marks + float radius; + //! Color intensity + float intensity; + //! Draw position for marks + Math::Vector drawPos; + //! Radius for marks + float drawRadius; + //! Draw intensity for marks + float drawIntensity; + //! X dimension of table + int dx; + //! Y dimension of table + int dy; + //! Pointer to the table + char* table; + + EngineGroundMark() + { + draw = false; + delay[0] = delay[1] = delay[2] = 0.0f; + fix = radius = intensity = drawRadius = drawIntensity = 0.0f; + dx = dy = 0; + table = NULL; + } +}; + +/** + \enum EngineTextureMapping + \brief Type of texture mapping + */ +enum EngineTextureMapping +{ + ENG_TEX_MAPPING_X = 1, + ENG_TEX_MAPPING_Y = 2, + ENG_TEX_MAPPING_Z = 3, + ENG_TEX_MAPPING_1X = 4, + ENG_TEX_MAPPING_1Y = 5, + ENG_TEX_MAPPING_1Z = 6 +}; + + +/** + \enum EngineRenderState + \brief Render state of graphics engine + + States are used for settings certain modes, for instance texturing and blending. + The enum is a bitmask and some of the states can be OR'd together. */ +enum EngineRenderState +{ + //! Normal opaque materials + ENG_RSTATE_NORMAL = 0, + //! The transparent texture (black = no) + ENG_RSTATE_TTEXTURE_BLACK = (1<<0), + //! The transparent texture (white = no) + ENG_RSTATE_TTEXTURE_WHITE = (1<<1), + //! The transparent diffuse color + ENG_RSTATE_TDIFFUSE = (1<<2), + //! Texture wrap + ENG_RSTATE_WRAP = (1<<3), + //! Texture borders with solid color + ENG_RSTATE_CLAMP = (1<<4), + //! Light texture (ambient max) + ENG_RSTATE_LIGHT = (1<<5), + //! Double black texturing + ENG_RSTATE_DUAL_BLACK = (1<<6), + //! Double white texturing + ENG_RSTATE_DUAL_WHITE = (1<<7), + //! Part 1 (no change in. MOD!) + ENG_RSTATE_PART1 = (1<<8), + //! Part 2 + ENG_RSTATE_PART2 = (1<<9), + //! Part 3 + ENG_RSTATE_PART3 = (1<<10), + //! Part 4 + ENG_RSTATE_PART4 = (1<<11), + //! Double-sided face + ENG_RSTATE_2FACE = (1<<12), + //! Image using alpha channel + ENG_RSTATE_ALPHA = (1<<13), + //! Always use 2nd floor texturing + ENG_RSTATE_SECOND = (1<<14), + //! Causes the fog + ENG_RSTATE_FOG = (1<<15), + //! The transparent color (black = no) + ENG_RSTATE_TCOLOR_BLACK = (1<<16), + //! The transparent color (white = no) + ENG_RSTATE_TCOLOR_WHITE = (1<<17) +}; + + +/** + \enum EngineMouseType + \brief Type of mouse cursor displayed in-game */ +enum EngineMouseType +{ + //! Normal cursor (arrow) + ENG_MOUSE_NORM = 0, + //! Busy + ENG_MOUSE_WAIT = 1, + //! Edit (I-beam) + ENG_MOUSE_EDIT = 2, + //! Hand + ENG_MOUSE_HAND = 3, + //! Small cross + ENG_MOUSE_CROSS = 4, + //! TODO: ? + ENG_MOUSE_SHOW = 5, + //! Crossed out sign + ENG_MOUSE_NO = 6, + //! Resize + ENG_MOUSE_MOVE = 7, + //! Resize horizontally + ENG_MOUSE_MOVEH = 8, + //! Resize vertically + ENG_MOUSE_MOVEV = 9, + //! Resize diagonally bottom-left to top-right + ENG_MOUSE_MOVED = 10, + //! Resize diagonally top-left to bottom-right + ENG_MOUSE_MOVEI = 11, + //! Scroll to the left + ENG_MOUSE_SCROLLL = 12, + //! Scroll to the right + ENG_MOUSE_SCROLLR = 13, + //! Scroll up + ENG_MOUSE_SCROLLU = 14, + //! Scroll down + ENG_MOUSE_SCROLLD = 15, + //! Larger crosshair + ENG_MOUSE_TARGET = 16, + + //! Number of items in enum + ENG_MOUSE_COUNT +}; + +/** + \struct EngineMouse + \brief Information about mouse cursor */ +struct EngineMouse +{ + //! Index of texture element for 1st image + int icon1; + //! Index of texture element for 2nd image + int icon2; + //! Shadow texture part + int iconShadow; + //! Mode to render 1st image in + Gfx::EngineRenderState mode1; + //! Mode to render 2nd image in + Gfx::EngineRenderState mode2; + //! Hot point + Math::Point hotPoint; + + EngineMouse(int icon1 = -1, int icon2 = -1, int iconShadow = -1, + Gfx::EngineRenderState mode1 = Gfx::ENG_RSTATE_NORMAL, + Gfx::EngineRenderState mode2 = Gfx::ENG_RSTATE_NORMAL, + Math::Point hotPoint = Math::Point()) + { + this->icon1 = icon1; + this->icon2 = icon2; + this->iconShadow = iconShadow; + this->mode1 = mode1; + this->mode2 = mode2; + this->hotPoint = hotPoint; + } +}; + + +/** + \class CEngine + \brief The graphics engine + + This is the main class for graphics engine. It is responsible for drawing the 3D scene, + setting various render states, and facilitating the drawing of 2D interface. + + It uses a lower-level CDevice object which is implementation-independent core engine. + + \section Objecs Engine objects + + The 3D scene is composed of objects which are basically collections of triangles forming + a surface or simply independent triangles in space. Objects are stored in the engine + as a tree structure which is composed of 5 tiers (EngineObjLevel1, EngineObjLevel2 and so on). + Each tier stores some data about object triangle, like textures or materials used. + Additional information on objects stored are in EngineObject structure. + Each object is uniquely identified by its rank. + + ... + */ +class CEngine +{ +public: + CEngine(CInstanceManager *iMan, CApplication *app); + ~CEngine(); + + //! Returns whether the device was initialized + bool GetWasInit(); + //! Returns the last error encountered + std::string GetError(); + + //! Performs the first initialization, before a device was set + bool Create(); + //! Frees all resources before exit + void Destroy(); + + //! Sets the device to be used + void SetDevice(Gfx::CDevice *device); + //! Returns the current device + Gfx::CDevice* GetDevice(); + + //! Performs initialization after a device was created and set + bool AfterDeviceSetInit(); + + //! Resets some states and flushes textures after device was changed (e.g. resoulution changed) + void ResetAfterDeviceChanged(); + + void SetTerrain(Gfx::CTerrain* terrain); + + //! Processes incoming event + bool ProcessEvent(const Event &event); + + //! Renders a single frame + bool Render(); + + + bool WriteProfile(); + + void SetPause(bool pause); + bool GetPause(); + + void SetMovieLock(bool lock); + bool GetMovieLock(); + + void SetShowStat(bool show); + bool GetShowStat(); + + void SetRenderEnable(bool enable); + + int OneTimeSceneInit(); + int InitDeviceObjects(); + int DeleteDeviceObjects(); + int RestoreSurfaces(); + int FrameMove(float rTime); + void StepSimulation(float rTime); + int FinalCleanup(); + void AddStatisticTriangle(int nb); + int GetStatisticTriangle(); + void SetHiliteRank(int *rankList); + bool GetHilite(Math::Point &p1, Math::Point &p2); + bool GetSpriteCoord(int &x, int &y); + void SetInfoText(int line, char* text); + char* GetInfoText(int line); + void FirstExecuteAdapt(bool first); + + bool GetFullScreen(); + + Math::Matrix* GetMatView(); + Math::Matrix* GetMatLeftView(); + Math::Matrix* GetMatRightView(); + + void TimeInit(); + void TimeEnterGel(); + void TimeExitGel(); + float TimeGet(); + + int GetRestCreate(); + int CreateObject(); + void FlushObject(); + bool DeleteObject(int objRank); + bool SetDrawWorld(int objRank, bool draw); + bool SetDrawFront(int objRank, bool draw); + + bool AddTriangle(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat, + int state, std::string texName1, std::string texName2, + float min, float max, bool globalUpdate); + bool AddSurface(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat, + int state, std::string texName1, std::string texName2, + float min, float max, bool globalUpdate); + bool AddQuick(int objRank, Gfx::EngineObjLevel5* buffer, + std::string texName1, std::string texName2, + float min, float max, bool globalUpdate); + Gfx::EngineObjLevel5* SearchTriangle(int objRank, const Gfx::Material &mat, + int state, std::string texName1, std::string texName2, + float min, float max); + + void ChangeLOD(); + bool ChangeSecondTexture(int objRank, char* texName2); + int GetTotalTriangles(int objRank); + int GetTriangles(int objRank, float min, float max, Gfx::EngineTriangle* buffer, int size, float percent); + bool GetBBox(int objRank, Math::Vector &min, Math::Vector &max); + bool ChangeTextureMapping(int objRank, const Gfx::Material &mat, int state, + const std::string &texName1, const std::string &texName2, + float min, float max, Gfx::EngineTextureMapping mode, + float au, float bu, float av, float bv); + bool TrackTextureMapping(int objRank, const Gfx::Material &mat, int state, + const std::string &texName1, const std::string &texName2, + float min, float max, Gfx::EngineTextureMapping mode, + float pos, float factor, float tl, float ts, float tt); + bool SetObjectTransform(int objRank, const Math::Matrix &transform); + bool GetObjectTransform(int objRank, Math::Matrix &transform); + bool SetObjectType(int objRank, Gfx::EngineObjectType type); + Gfx::EngineObjectType GetObjectType(int objRank); + bool SetObjectTransparency(int objRank, float value); + + bool ShadowCreate(int objRank); + void ShadowDelete(int objRank); + bool SetObjectShadowHide(int objRank, bool hide); + bool SetObjectShadowType(int objRank, Gfx::EngineShadowType type); + bool SetObjectShadowPos(int objRank, const Math::Vector &pos); + bool SetObjectShadowNormal(int objRank, const Math::Vector &n); + bool SetObjectShadowAngle(int objRank, float angle); + bool SetObjectShadowRadius(int objRank, float radius); + bool SetObjectShadowIntensity(int objRank, float intensity); + bool SetObjectShadowHeight(int objRank, float h); + float GetObjectShadowRadius(int objRank); + + void GroundSpotFlush(); + int GroundSpotCreate(); + void GroundSpotDelete(int rank); + bool SetObjectGroundSpotPos(int rank, const Math::Vector &pos); + bool SetObjectGroundSpotRadius(int rank, float radius); + bool SetObjectGroundSpotColor(int rank, const Gfx::Color &color); + bool SetObjectGroundSpotMinMax(int rank, float min, float max); + bool SetObjectGroundSpotSmooth(int rank, float smooth); + + int GroundMarkCreate(Math::Vector pos, float radius, + float delay1, float delay2, float delay3, + int dx, int dy, char* table); + bool GroundMarkDelete(int rank); + + void Update(); + + void SetViewParams(const Math::Vector &eyePt, const Math::Vector &lookatPt, + const Math::Vector &upVec, float eyeDistance); + + Gfx::Texture CreateTexture(const std::string &texName, + const Gfx::TextureCreateParams ¶ms); + Gfx::Texture CreateTexture(const std::string &texName); + void DestroyTexture(const std::string &texName); + + bool LoadTexture(const std::string &name, int stage = 0); + bool LoadAllTextures(); + + void SetLimitLOD(int rank, float limit); + float GetLimitLOD(int rank, bool last=false); + + void SetTerrainVision(float vision); + + void SetGroundSpot(bool mode); + bool GetGroundSpot(); + void SetShadow(bool mode); + bool GetShadow(); + void SetDirty(bool mode); + bool GetDirty(); + void SetFog(bool mode); + bool GetFog(); + bool GetStateColor(); + + void SetSecondTexture(int texNum); + int GetSecondTexture(); + + void SetRankView(int rank); + int GetRankView(); + + void SetDrawWorld(bool draw); + void SetDrawFront(bool draw); + + void SetAmbientColor(const Gfx::Color &color, int rank = 0); + Gfx::Color GetAmbientColor(int rank = 0); + + void SetWaterAddColor(const Gfx::Color &color); + Gfx::Color GetWaterAddColor(); + + void SetFogColor(const Gfx::Color &color, int rank = 0); + Gfx::Color GetFogColor(int rank = 0); + + void SetDeepView(float length, int rank = 0, bool ref=false); + float GetDeepView(int rank = 0); + + void SetFogStart(float start, int rank = 0); + float GetFogStart(int rank = 0); + + void SetBackground(const std::string &name, Gfx::Color up = Gfx::Color(), Gfx::Color down = Gfx::Color(), + Gfx::Color cloudUp = Gfx::Color(), Gfx::Color cloudDown = Gfx::Color(), + bool full = false, bool quarter = false); + void GetBackground(const std::string &name, Gfx::Color &up, Gfx::Color &down, + Gfx::Color &cloudUp, Gfx::Color &cloudDown, + bool &full, bool &quarter); + void SetFrontsizeName(char *name); + void SetOverFront(bool front); + void SetOverColor(const Gfx::Color &color = Gfx::Color(), int mode = ENG_RSTATE_TCOLOR_BLACK); + + void SetParticleDensity(float value); + float GetParticleDensity(); + float ParticleAdapt(float factor); + + void SetClippingDistance(float value); + float GetClippingDistance(); + + void SetObjectDetail(float value); + float GetObjectDetail(); + + void SetGadgetQuantity(float value); + float GetGadgetQuantity(); + + void SetTextureQuality(int value); + int GetTextureQuality(); + + void SetTotoMode(bool present); + bool GetTotoMode(); + + void SetLensMode(bool present); + bool GetLensMode(); + + void SetWaterMode(bool present); + bool GetWaterMode(); + + void SetLightingMode(bool present); + bool GetLightingMode(); + + void SetSkyMode(bool present); + bool GetSkyMode(); + + void SetBackForce(bool present); + bool GetBackForce(); + + void SetPlanetMode(bool present); + bool GetPlanetMode(); + + void SetLightMode(bool present); + bool GetLightMode(); + + void SetEditIndentMode(bool autoIndent); + bool GetEditIndentMode(); + + void SetEditIndentValue(int value); + int GetEditIndentValue(); + + void SetSpeed(float speed); + float GetSpeed(); + + void SetTracePrecision(float factor); + float GetTracePrecision(); + + void SetFocus(float focus); + float GetFocus(); + Math::Vector GetEyePt(); + Math::Vector GetLookatPt(); + float GetEyeDirH(); + float GetEyeDirV(); + Math::Point GetDim(); + void UpdateMatProj(); + + void ApplyChange(); + + void FlushPressKey(); + void ResetKey(); + void SetKey(int keyRank, int option, int key); + int GetKey(int keyRank, int option); + + void SetJoystick(bool enable); + bool GetJoystick(); + + void SetDebugMode(bool mode); + bool GetDebugMode(); + bool GetSetupMode(); + + bool IsVisiblePoint(const Math::Vector &pos); + + int DetectObject(Math::Point mouse); + void SetState(int state, Gfx::Color color = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)); + void SetTexture(const std::string &name, int stage = 0); + void SetMaterial(const Gfx::Material &mat); + + void SetMouseVisible(bool show); + bool GetMouseVisible(); + void SetMousePos(Math::Point pos); + Math::Point GetMousePos(); + void SetMouseType(Gfx::EngineMouseType type); + Gfx::EngineMouseType GetMouseType(); + + CText* GetText(); + + bool ChangeColor(char *name, Gfx::Color colorRef1, Gfx::Color colorNew1, + Gfx::Color colorRef2, Gfx::Color colorNew2, + float tolerance1, float tolerance2, + Math::Point ts, Math::Point ti, + Math::Point *pExclu=0, float shift=0.0f, bool hSV=false); + bool OpenImage(char *name); + bool CopyImage(); + bool LoadImage(); + bool ScrollImage(int dx, int dy); + bool SetDot(int x, int y, Gfx::Color color); + bool CloseImage(); + bool WriteScreenShot(char *filename, int width, int height); + //bool GetRenderDC(HDC &hDC); + //bool ReleaseRenderDC(HDC &hDC); + //PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp); + //bool CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC); + +protected: + + void SetUp3DView(); + bool Draw3DScene(); + + void SetUpInterfaceView(); + bool DrawInterface(); + + void DrawGroundSpot(); + void DrawShadow(); + void DrawBackground(); + void DrawBackgroundGradient(Gfx::Color up, Gfx::Color down); + void DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, char *name); + void DrawBackgroundImage(); + void DrawPlanet(); + void DrawFrontsize(); + void DrawOverColor(); + void DrawHilite(); + void DrawMouse(); + void DrawMouseSprite(Math::Point pos, Math::Point dim, int icon); + + /* + Gfx::ObjLevel2* AddLevel1(Gfx::ObjLevel1 *&p1, char* texName1, char* texName2); + Gfx::ObjLevel3* AddLevel2(Gfx::ObjLevel2 *&p2, int objRank); + Gfx::ObjLevel4* AddLevel3(Gfx::ObjLevel3 *&p3, float min, float max); + Gfx::ObjLevel5* AddLevel4(Gfx::ObjLevel4 *&p4, int reserve); + Gfx::ObjLevel6* AddLevel5(Gfx::ObjLevel5 *&p5, Gfx::TriangleType type, const Gfx::Material &mat, int state, int nb);*/ + + bool IsVisible(int objRank); + bool DetectBBox(int objRank, Math::Point mouse); + bool GetBBox2D(int objRank, Math::Point &min, Math::Point &max); + bool DetectTriangle(Math::Point mouse, Gfx::VertexTex2 *triangle, int objRank, float &dist); + bool TransformPoint(Math::Vector &p2D, int objRank, Math::Vector p3D); + void ComputeDistance(); + void UpdateGeometry(); + +protected: + CInstanceManager* m_iMan; + CApplication* m_app; + CSound* m_sound; + Gfx::CDevice* m_device; + Gfx::CText* m_text; + Gfx::CLightManager* m_lightMan; + Gfx::CParticle* m_particle; + Gfx::CWater* m_water; + Gfx::CCloud* m_cloud; + Gfx::CLightning* m_lightning; + Gfx::CPlanet* m_planet; + Gfx::CTerrain* m_terrain; + + bool m_wasInit; + std::string m_error; + + //! Whether to show stats (FPS, etc) + bool m_showStats; + + int m_blackSrcBlend[2]; + int m_blackDestBlend[2]; + int m_whiteSrcBlend[2]; + int m_whiteDestBlend[2]; + int m_diffuseSrcBlend[2]; + int m_diffuseDestBlend[2]; + int m_alphaSrcBlend[2]; + int m_alphaDestBlend[2]; + + Math::Matrix m_matProj; + Math::Matrix m_matLeftView; + Math::Matrix m_matRightView; + Math::Matrix m_matView; + float m_focus; + + Math::Matrix m_matWorldInterface; + Math::Matrix m_matProjInterface; + Math::Matrix m_matViewInterface; + + long m_baseTime; + long m_stopTime; + float m_absTime; + float m_lastTime; + float m_speed; + bool m_pause; + bool m_render; + bool m_movieLock; + + //! Current size of window + Math::IntSize m_size; + Math::IntSize m_lastSize; + + std::vector<Gfx::EngineObjLevel1> m_objectTree; + std::vector<Gfx::EngineObject> m_objects; + std::vector<Gfx::EngineShadow> m_shadow; + std::vector<Gfx::EngineGroundSpot> m_groundSpot; + Gfx::EngineGroundMark m_groundMark; + + Math::Vector m_eyePt; + Math::Vector m_lookatPt; + float m_eyeDirH; + float m_eyeDirV; + int m_rankView; + Gfx::Color m_ambientColor[2]; + Gfx::Color m_backColor[2]; + Gfx::Color m_fogColor[2]; + float m_deepView[2]; + float m_fogStart[2]; + Gfx::Color m_waterAddColor; + int m_statisticTriangle; + bool m_updateGeometry; + //char m_infoText[10][200]; + int m_alphaMode; + bool m_stateColor; + bool m_forceStateColor; + bool m_groundSpotVisible; + bool m_shadowVisible; + bool m_dirty; + bool m_fog; + bool m_firstGroundSpot; + int m_secondTexNum; + std::string m_backgroundName; + Gfx::Color m_backgroundColorUp; + Gfx::Color m_backgroundColorDown; + Gfx::Color m_backgroundCloudUp; + Gfx::Color m_backgroundCloudDown; + bool m_backgroundFull; + bool m_backgroundQuarter; + bool m_overFront; + Gfx::Color m_overColor; + int m_overMode; + std::string m_frontsizeName; + bool m_drawWorld; + bool m_drawFront; + float m_limitLOD[2]; + float m_particuleDensity; + float m_clippingDistance; + float m_lastClippingDistance; + float m_objectDetail; + float m_lastObjectDetail; + float m_terrainVision; + float m_gadgetQuantity; + int m_textureQuality; + bool m_totoMode; + bool m_lensMode; + bool m_waterMode; + bool m_skyMode; + bool m_backForce; + bool m_planetMode; + bool m_lightMode; + bool m_editIndentMode; + int m_editIndentValue; + float m_tracePrecision; + + int m_hiliteRank[100]; + bool m_hilite; + Math::Point m_hiliteP1; + Math::Point m_hiliteP2; + + int m_lastState; + Gfx::Color m_lastColor; + char m_lastTexture[2][50]; + Gfx::Material m_lastMaterial; + + std::string m_texPath; + Gfx::TextureCreateParams m_defaultTexParams; + + std::map<std::string, Gfx::Texture> m_texNameMap; + std::map<Gfx::Texture, std::string> m_revTexNameMap; + + Gfx::EngineMouse m_mice[Gfx::ENG_MOUSE_COUNT]; + Gfx::Texture m_miceTexture; + Math::Point m_mouseSize; + Gfx::EngineMouseType m_mouseType; + Math::Point m_mousePos; + bool m_mouseVisible; + + //LPDIRECTDRAWSURFACE7 m_imageSurface; + //DDSURFACEDESC2 m_imageDDSD; + //WORD* m_imageCopy; + //int m_imageDX; + //int m_imageDY; +}; + +}; // namespace Gfx diff --git a/src/graphics/engine/lightman.cpp b/src/graphics/engine/lightman.cpp new file mode 100644 index 0000000..9e15b5a --- /dev/null +++ b/src/graphics/engine/lightman.cpp @@ -0,0 +1,416 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * 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/. + +// light.cpp + +#include "graphics/engine/lightman.h" + +#include "common/iman.h" +#include "graphics/core/device.h" +#include "math/geometry.h" + +#include <cmath> + + +void Gfx::LightProgression::Init(float value) +{ + starting = value; + ending = value; + current = value; + progress = 0.0f; + speed = 100.0f; +} + +void Gfx::LightProgression::Update(float rTime) +{ + if (speed < 100.0f) + { + if (progress < 1.0f) + { + progress += speed * rTime; + if (progress > 1.0f) + progress = 1.0f; + } + + current = starting + progress * (ending - starting); + } + else + { + current = ending; + } +} + +void Gfx::LightProgression::SetTarget(float value) +{ + starting = current; + ending = value; + progress = 0.0f; +} + + +Gfx::DynamicLight::DynamicLight() +{ + used = enabled = false; +} + + + +Gfx::CLightManager::CLightManager(CInstanceManager* iMan, Gfx::CEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_LIGHT, this); + + m_device = NULL; + m_engine = engine; + + m_time = 0.0f; +} + +Gfx::CLightManager::~CLightManager() +{ + m_iMan->DeleteInstance(CLASS_LIGHT, this); + + m_iMan = NULL; + m_device = NULL; + m_engine = NULL; +} + +void Gfx::CLightManager::SetDevice(Gfx::CDevice* device) +{ + m_device = device; + + m_dynLights = std::vector<Gfx::DynamicLight>(m_device->GetMaxLightCount(), Gfx::DynamicLight()); +} + +void Gfx::CLightManager::FlushLights() +{ + for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++) + { + m_dynLights[i].used = false; + m_device->SetLightEnabled(i, false); + } +} + +/** Returns the index of light created or -1 if all lights are used. */ +int Gfx::CLightManager::CreateLight() +{ + for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++) + { + if (m_dynLights[i].used) continue; + + m_dynLights[i] = Gfx::DynamicLight(); + + m_dynLights[i].used = true; + m_dynLights[i].enabled = true; + + m_dynLights[i].includeType = Gfx::ENG_OBJTYPE_NULL; + m_dynLights[i].excludeType = Gfx::ENG_OBJTYPE_NULL; + + m_dynLights[i].light.type = Gfx::LIGHT_DIRECTIONAL; + m_dynLights[i].light.diffuse = Gfx::Color(0.5f, 0.5f, 0.5f); + m_dynLights[i].light.position = Math::Vector(-100.0f, 100.0f, -100.0f); + m_dynLights[i].light.direction = Math::Vector( 1.0f, -1.0f, 1.0f); + + m_dynLights[i].intensity.Init(1.0f); // maximum + m_dynLights[i].colorRed.Init(0.5f); + m_dynLights[i].colorGreen.Init(0.5f); + m_dynLights[i].colorBlue.Init(0.5f); // gray + + return i; + } + + return -1; +} + +bool Gfx::CLightManager::DeleteLight(int lightRank) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].used = false; + m_device->SetLightEnabled(lightRank, false); + + return true; +} + +// Specifies a light. + +bool Gfx::CLightManager::SetLight(int lightRank, const Gfx::Light &light) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].light = light; + + m_dynLights[lightRank].colorRed.Init(m_dynLights[lightRank].light.diffuse.r); + m_dynLights[lightRank].colorGreen.Init(m_dynLights[lightRank].light.diffuse.g); + m_dynLights[lightRank].colorBlue.Init(m_dynLights[lightRank].light.diffuse.b); + + return true; +} + +bool Gfx::CLightManager::GetLight(int lightRank, Gfx::Light &light) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + light = m_dynLights[lightRank].light; + return true; +} + +bool Gfx::CLightManager::SetLightEnabled(int lightRank, bool enabled) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].enabled = enabled; + return true; +} + +bool Gfx::CLightManager::SetLightIncludeType(int lightRank, Gfx::EngineObjectType type) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].includeType = type; + return true; +} + +bool Gfx::CLightManager::SetLightExcludeType(int lightRank, Gfx::EngineObjectType type) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].excludeType = type; + return true; +} + +bool Gfx::CLightManager::SetLightPos(int lightRank, const Math::Vector &pos) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].light.position = pos; + return true; +} + +Math::Vector Gfx::CLightManager::GetLightPos(int lightRank) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return Math::Vector(0.0f, 0.0f, 0.0f); + + return m_dynLights[lightRank].light.position; +} + +bool Gfx::CLightManager::SetLightDir(int lightRank, const Math::Vector &dir) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].light.direction = dir; + return true; +} + +Math::Vector Gfx::CLightManager::GetLightDir(int lightRank) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return Math::Vector(0.0f, 0.0f, 0.0f); + + return m_dynLights[lightRank].light.direction; +} + +bool Gfx::CLightManager::SetLightIntensitySpeed(int lightRank, float speed) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].intensity.speed = speed; + return true; +} + +bool Gfx::CLightManager::SetLightIntensity(int lightRank, float value) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].intensity.SetTarget(value); + return true; +} + +float Gfx::CLightManager::GetLightIntensity(int lightRank) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return 0.0f; + + return m_dynLights[lightRank].intensity.current; +} + + +bool Gfx::CLightManager::SetLightColorSpeed(int lightRank, float speed) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].colorRed.speed = speed; + m_dynLights[lightRank].colorGreen.speed = speed; + m_dynLights[lightRank].colorBlue.speed = speed; + return true; +} + +bool Gfx::CLightManager::SetLightColor(int lightRank, const Gfx::Color &color) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return false; + + m_dynLights[lightRank].colorRed.SetTarget(color.r); + m_dynLights[lightRank].colorGreen.SetTarget(color.g); + m_dynLights[lightRank].colorBlue.SetTarget(color.b); + return true; +} + +Gfx::Color Gfx::CLightManager::GetLightColor(int lightRank) +{ + if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) ) + return Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f); + + Gfx::Color color; + color.r = m_dynLights[lightRank].colorRed.current; + color.g = m_dynLights[lightRank].colorGreen.current; + color.b = m_dynLights[lightRank].colorBlue.current; + return color; +} + +void Gfx::CLightManager::AdaptLightColor(const Gfx::Color &color, float factor) +{ + for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++) + { + if (! m_dynLights[i].used) + continue; + + Gfx::Color value; + value.r = m_dynLights[i].colorRed.current; + value.g = m_dynLights[i].colorGreen.current; + value.b = m_dynLights[i].colorBlue.current; + + value.r += color.r * factor; + value.g += color.g * factor; + value.b += color.b * factor; + + m_dynLights[i].colorRed.Init(value.r); + m_dynLights[i].colorGreen.Init(value.g); + m_dynLights[i].colorBlue.Init(value.b); + } + + UpdateLights(); +} + +void Gfx::CLightManager::UpdateProgression(float rTime) +{ + if (m_engine->GetPause()) + return; + + m_time += rTime; + + for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++) + { + if (! m_dynLights[i].used) + continue; + + m_dynLights[i].intensity.Update(rTime); + m_dynLights[i].colorRed.Update(rTime); + m_dynLights[i].colorGreen.Update(rTime); + m_dynLights[i].colorBlue.Update(rTime); + + if (m_dynLights[i].includeType == Gfx::ENG_OBJTYPE_QUARTZ) + { + m_dynLights[i].light.direction.x = sinf(1.0f * (m_time + i*Math::PI*0.5f)); + m_dynLights[i].light.direction.z = cosf(1.1f * (m_time + i*Math::PI*0.5f)); + m_dynLights[i].light.direction.y = -1.0f + 0.5f * cosf((m_time + i*Math::PI*0.5f)*2.7f); + } + + if (m_dynLights[i].includeType == Gfx::ENG_OBJTYPE_METAL) + { + Math::Vector dir = m_engine->GetEyePt() - m_engine->GetLookatPt(); + float angle = Math::RotateAngle(dir.x, dir.z); + angle += Math::PI * 0.5f * i; + m_dynLights[i].light.direction.x = sinf(2.0f * angle); + m_dynLights[i].light.direction.z = cosf(2.0f * angle); + } + } +} + + +void Gfx::CLightManager::UpdateLights() +{ + for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++) + { + if (! m_dynLights[i].used) + continue; + + bool enabled = m_dynLights[i].enabled; + if (m_dynLights[i].intensity.current == 0.0f) + enabled = false; + + if (enabled) + { + float value = m_dynLights[i].colorRed.current * m_dynLights[i].intensity.current; + m_dynLights[i].light.diffuse.r = value; + + value = m_dynLights[i].colorGreen.current * m_dynLights[i].intensity.current; + m_dynLights[i].light.diffuse.g = value; + + value = m_dynLights[i].colorBlue.current * m_dynLights[i].intensity.current; + m_dynLights[i].light.diffuse.b = value; + + m_device->SetLight(i, m_dynLights[i].light); + m_device->SetLightEnabled(i, enabled); + } + else + { + m_dynLights[i].light.diffuse.r = 0.0f; + m_dynLights[i].light.diffuse.g = 0.0f; + m_dynLights[i].light.diffuse.b = 0.0f; + + m_device->SetLightEnabled(i, enabled); + } + } +} + +void Gfx::CLightManager::UpdateLightsEnableState(Gfx::EngineObjectType type) +{ + for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++) + { + if (! m_dynLights[i].used) + continue; + if (! m_dynLights[i].enabled) + continue; + if (m_dynLights[i].intensity.current == 0.0f) + continue; + + if (m_dynLights[i].includeType != Gfx::ENG_OBJTYPE_NULL) + { + bool enabled = (m_dynLights[i].includeType == type); + m_device->SetLightEnabled(i, enabled); + } + + if (m_dynLights[i].excludeType != Gfx::ENG_OBJTYPE_NULL) + { + bool enabled = (m_dynLights[i].excludeType != type); + m_device->SetLightEnabled(i, enabled); + } + } +} diff --git a/src/graphics/engine/lightman.h b/src/graphics/engine/lightman.h new file mode 100644 index 0000000..8272125 --- /dev/null +++ b/src/graphics/engine/lightman.h @@ -0,0 +1,181 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * 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/. + +// lightman.h + +#pragma once + + +#include "graphics/core/color.h" +#include "graphics/core/light.h" +#include "graphics/engine/engine.h" +#include "math/vector.h" + + +namespace Gfx { + +/** + \struct LightProgression + \brief Describes the progression of light parameters change */ +struct LightProgression +{ + //! Starting value + float starting; + //! Ending (destination) value + float ending; + //! Current value + float current; + //! Progress from start to end + float progress; + //! Speed of progression + float speed; + + LightProgression() + { + starting = ending = current = progress = speed = 0.0f; + } + + //! Initializes the progression + void Init(float value); + + //! Updates the progression + void Update(float rTime); + + //! Sets the new end value (starting is set to current) + void SetTarget(float value); +}; + +/** + \struct DynamicLight + \brief Dynamic light in 3D scene + + It is an extension over standard light properties. Added are dynamic progressions for light + colors and intensity and types of objects included/excluded in lighting. */ +struct DynamicLight +{ + //! Whether the light is used + bool used; + //! Whether the light is turned on + bool enabled; + + //! Configuration of the light + Gfx::Light light; + + //! Progression of intensity [0, 1] + Gfx::LightProgression intensity; + //! Progression of red diffuse color + Gfx::LightProgression colorRed; + //! Progression of green diffuse color + Gfx::LightProgression colorGreen; + //! Progression of blue diffuse color + Gfx::LightProgression colorBlue; + + //! Type of objects included in lighting with this light; if Gfx::ENG_OBJTYPE_NULL is used, it is ignored + Gfx::EngineObjectType includeType; + //! Type of objects excluded from lighting with this light; if Gfx::ENG_OBJTYPE_NULL is used, it is ignored + Gfx::EngineObjectType excludeType; + + DynamicLight(); +}; + +/** + \class CLightManager + \brief Manager for dynamic lights in 3D scene + + (Old CLight class) + + The class is responsible for managing dynamic lights (struct Gfx::DynamicLight) used in 3D scene. + The dynamic lights are created, updated and deleted through the class' interface. + + Number of available lights depends on graphics device used. Class allocates vector + for the total number of lights, but only some are used. + */ +class CLightManager +{ +public: + //! Constructor + CLightManager(CInstanceManager *iMan, Gfx::CEngine* engine); + //! Destructor + virtual ~CLightManager(); + + //! Sets the device to be used + void SetDevice(Gfx::CDevice* device); + + //! Clears and disables all lights + void FlushLights(); + //! Creates a new dynamic light and returns its index (lightRank) + int CreateLight(); + //! Deletes and disables the given dynamic light + bool DeleteLight(int lightRank); + //! Sets the light parameters for dynamic light + bool SetLight(int lightRank, const Gfx::Light &light); + //! Returns the light parameters for given dynamic light + bool GetLight(int lightRank, Gfx::Light &light); + //! Enables/disables the given dynamic light + bool SetLightEnabled(int lightRank, bool enable); + + //! Sets what objects are included in given dynamic light + bool SetLightIncludeType(int lightRank, Gfx::EngineObjectType type); + //! Sets what objects are excluded from given dynamic light + bool SetLightExcludeType(int lightRank, Gfx::EngineObjectType type); + + //! Sets the position of dynamic light + bool SetLightPos(int lightRank, const Math::Vector &pos); + //! Returns the position of dynamic light + Math::Vector GetLightPos(int lightRank); + + //! Sets the direction of dynamic light + bool SetLightDir(int lightRank, const Math::Vector &dir); + //! Returns the direction of dynamic light + Math::Vector GetLightDir(int lightRank); + + //! Sets the destination intensity for dynamic light's intensity progression + bool SetLightIntensity(int lightRank, float value); + //! Returns the current light intensity + float GetLightIntensity(int lightRank); + //! Sets the rate of change for dynamic light intensity + bool SetLightIntensitySpeed(int lightRank, float speed); + + //! Adjusts the color of all dynamic lights + void AdaptLightColor(const Gfx::Color &color, float factor); + + //! Sets the destination color for dynamic light's color progression + bool SetLightColor(int lightRank, const Gfx::Color &color); + //! Returns current light color + Gfx::Color GetLightColor(int lightRank); + //! Sets the rate of change for dynamic light colors (RGB) + bool SetLightColorSpeed(int lightRank, float speed); + + //! Updates progression of dynamic lights + void UpdateProgression(float rTime); + //! Updates (recalculates) all dynamic lights + void UpdateLights(); + //! Enables or disables dynamic lights affecting the given object type + void UpdateLightsEnableState(Gfx::EngineObjectType type); + +protected: + CInstanceManager* m_iMan; + CEngine* m_engine; + CDevice* m_device; + + //! Current time + float m_time; + //! List of dynamic lights + std::vector<Gfx::DynamicLight> m_dynLights; +}; + +}; // namespace Gfx diff --git a/src/graphics/common/lightning.cpp b/src/graphics/engine/lightning.cpp index 076fcb4..4db5511 100644 --- a/src/graphics/common/lightning.cpp +++ b/src/graphics/engine/lightning.cpp @@ -17,7 +17,7 @@ // lightning.cpp (aka blitz.cpp) -#include "graphics/common/lightning.h" +#include "graphics/engine/lightning.h" // TODO implementation diff --git a/src/graphics/common/lightning.h b/src/graphics/engine/lightning.h index 957344c..957344c 100644 --- a/src/graphics/common/lightning.h +++ b/src/graphics/engine/lightning.h diff --git a/src/graphics/engine/modelfile.cpp b/src/graphics/engine/modelfile.cpp new file mode 100644 index 0000000..844958f --- /dev/null +++ b/src/graphics/engine/modelfile.cpp @@ -0,0 +1,841 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * 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/. + +// modelfile.cpp (aka modfile.cpp) + +#include "graphics/engine/modelfile.h" + +#include "common/iman.h" +#include "common/ioutils.h" +#include "common/logger.h" +#include "common/stringutils.h" +#include "math/geometry.h" + +#include <string.h> + +#include <fstream> + + +//! How big the triangle vector is by default +const int TRIANGLE_PREALLOCATE_COUNT = 2000; + +/** + \struct ModelHeader + \brief Header info for model file + */ +struct ModelHeader +{ + //! Revision number + int revision; + //! Version number + int version; + //! Total number of vertices + int totalVertices; + //! Reserved area + int reserved[10]; + + ModelHeader() + { + memset(this, 0, sizeof(*this)); + } +}; + + +struct OldModelTriangle1 +{ + char used; + char selected; + Gfx::Vertex p1; + Gfx::Vertex p2; + Gfx::Vertex p3; + Gfx::Material material; + char texName[20]; + float min; + float max; + + OldModelTriangle1() + { + memset(this, 0, sizeof(*this)); + } +}; + +struct OldModelTriangle2 +{ + char used; + char selected; + Gfx::Vertex p1; + Gfx::Vertex p2; + Gfx::Vertex p3; + Gfx::Material material; + char texName[20]; + float min; + float max; + long state; + short reserved1; + short reserved2; + short reserved3; + short reserved4; + OldModelTriangle2() + { + memset(this, 0, sizeof(*this)); + } +}; + + +struct NewModelTriangle +{ + char used; + char selected; + Gfx::VertexTex2 p1; + Gfx::VertexTex2 p2; + Gfx::VertexTex2 p3; + Gfx::Material material; + char texName[20]; + float min; + float max; + long state; + short texNum2; + short reserved2; + short reserved3; + short reserved4; + + NewModelTriangle() + { + memset(this, 0, sizeof(*this)); + } +}; + + +Gfx::Vertex ReadBinaryVertex(std::istream &stream) +{ + Gfx::Vertex result; + + result.coord.x = IOUtils::ReadBinaryFloat(stream); + result.coord.y = IOUtils::ReadBinaryFloat(stream); + result.coord.z = IOUtils::ReadBinaryFloat(stream); + result.normal.x = IOUtils::ReadBinaryFloat(stream); + result.normal.y = IOUtils::ReadBinaryFloat(stream); + result.normal.z = IOUtils::ReadBinaryFloat(stream); + result.texCoord.x = IOUtils::ReadBinaryFloat(stream); + result.texCoord.y = IOUtils::ReadBinaryFloat(stream); + + return result; +} + +void WriteBinaryVertex(Gfx::Vertex vertex, std::ostream &stream) +{ + IOUtils::WriteBinaryFloat(vertex.coord.x, stream); + IOUtils::WriteBinaryFloat(vertex.coord.y, stream); + IOUtils::WriteBinaryFloat(vertex.coord.z, stream); + IOUtils::WriteBinaryFloat(vertex.normal.x, stream); + IOUtils::WriteBinaryFloat(vertex.normal.y, stream); + IOUtils::WriteBinaryFloat(vertex.normal.z, stream); + IOUtils::WriteBinaryFloat(vertex.texCoord.x, stream); + IOUtils::WriteBinaryFloat(vertex.texCoord.y, stream); +} + +Gfx::VertexTex2 ReadBinaryVertexTex2(std::istream &stream) +{ + Gfx::VertexTex2 result; + + result.coord.x = IOUtils::ReadBinaryFloat(stream); + result.coord.y = IOUtils::ReadBinaryFloat(stream); + result.coord.z = IOUtils::ReadBinaryFloat(stream); + result.normal.x = IOUtils::ReadBinaryFloat(stream); + result.normal.y = IOUtils::ReadBinaryFloat(stream); + result.normal.z = IOUtils::ReadBinaryFloat(stream); + result.texCoord.x = IOUtils::ReadBinaryFloat(stream); + result.texCoord.y = IOUtils::ReadBinaryFloat(stream); + result.texCoord2.x = IOUtils::ReadBinaryFloat(stream); + result.texCoord2.y = IOUtils::ReadBinaryFloat(stream); + + return result; +} + +void WriteBinaryVertexTex2(Gfx::VertexTex2 vertex, std::ostream &stream) +{ + IOUtils::WriteBinaryFloat(vertex.coord.x, stream); + IOUtils::WriteBinaryFloat(vertex.coord.y, stream); + IOUtils::WriteBinaryFloat(vertex.coord.z, stream); + IOUtils::WriteBinaryFloat(vertex.normal.x, stream); + IOUtils::WriteBinaryFloat(vertex.normal.y, stream); + IOUtils::WriteBinaryFloat(vertex.normal.z, stream); + IOUtils::WriteBinaryFloat(vertex.texCoord.x, stream); + IOUtils::WriteBinaryFloat(vertex.texCoord.y, stream); + IOUtils::WriteBinaryFloat(vertex.texCoord2.x, stream); + IOUtils::WriteBinaryFloat(vertex.texCoord2.y, stream); +} + +Gfx::Material ReadBinaryMaterial(std::istream &stream) +{ + Gfx::Material result; + + result.diffuse.r = IOUtils::ReadBinaryFloat(stream); + result.diffuse.g = IOUtils::ReadBinaryFloat(stream); + result.diffuse.b = IOUtils::ReadBinaryFloat(stream); + result.diffuse.a = IOUtils::ReadBinaryFloat(stream); + + result.ambient.r = IOUtils::ReadBinaryFloat(stream); + result.ambient.g = IOUtils::ReadBinaryFloat(stream); + result.ambient.b = IOUtils::ReadBinaryFloat(stream); + result.ambient.a = IOUtils::ReadBinaryFloat(stream); + + result.specular.r = IOUtils::ReadBinaryFloat(stream); + result.specular.g = IOUtils::ReadBinaryFloat(stream); + result.specular.b = IOUtils::ReadBinaryFloat(stream); + result.specular.a = IOUtils::ReadBinaryFloat(stream); + + /* emissive.r = */ IOUtils::ReadBinaryFloat(stream); + /* emissive.g = */ IOUtils::ReadBinaryFloat(stream); + /* emissive.b = */ IOUtils::ReadBinaryFloat(stream); + /* emissive.a = */ IOUtils::ReadBinaryFloat(stream); + + /* power = */ IOUtils::ReadBinaryFloat(stream); + + return result; +} + +void WriteBinaryMaterial(Gfx::Material material, std::ostream &stream) +{ + IOUtils::WriteBinaryFloat(material.diffuse.r, stream); + IOUtils::WriteBinaryFloat(material.diffuse.g, stream); + IOUtils::WriteBinaryFloat(material.diffuse.b, stream); + IOUtils::WriteBinaryFloat(material.diffuse.a, stream); + + IOUtils::WriteBinaryFloat(material.ambient.r, stream); + IOUtils::WriteBinaryFloat(material.ambient.g, stream); + IOUtils::WriteBinaryFloat(material.ambient.b, stream); + IOUtils::WriteBinaryFloat(material.ambient.a, stream); + + IOUtils::WriteBinaryFloat(material.specular.r, stream); + IOUtils::WriteBinaryFloat(material.specular.g, stream); + IOUtils::WriteBinaryFloat(material.specular.b, stream); + IOUtils::WriteBinaryFloat(material.specular.a, stream); + + /* emissive.r */ IOUtils::WriteBinaryFloat(0.0f, stream); + /* emissive.g */ IOUtils::WriteBinaryFloat(0.0f, stream); + /* emissive.b */ IOUtils::WriteBinaryFloat(0.0f, stream); + /* emissive.a */ IOUtils::WriteBinaryFloat(0.0f, stream); + + /* power */ IOUtils::WriteBinaryFloat(0.0f, stream); +} + +Gfx::ModelTriangle::ModelTriangle() +{ + min = 0.0f; + max = 0.0f; + state = 0L; +} + + +Gfx::CModelFile::CModelFile(CInstanceManager* iMan) +{ + m_iMan = iMan; + + m_engine = static_cast<CEngine*>(m_iMan->SearchInstance(CLASS_ENGINE)); + + m_triangles.reserve(TRIANGLE_PREALLOCATE_COUNT); +} + +Gfx::CModelFile::~CModelFile() +{ +} + +std::string Gfx::CModelFile::GetError() +{ + return m_error; +} + + +bool Gfx::CModelFile::ReadModel(const std::string &filename, bool edit, bool meta) +{ + m_triangles.clear(); + m_error = ""; + + std::ifstream stream; + stream.open(filename.c_str(), std::ios_base::in | std::ios_base::binary); + if (! stream.good()) + { + m_error = std::string("Could not open file '") + filename + std::string("'"); + return false; + } + + return ReadModel(stream, edit, meta); +} + +bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta) +{ + m_triangles.clear(); + m_error = ""; + + // FIXME: for now, reading models only from files, not metafile + + ModelHeader header; + + header.revision = IOUtils::ReadBinary<4, int>(stream); + header.version = IOUtils::ReadBinary<4, int>(stream); + header.totalVertices = IOUtils::ReadBinary<4, int>(stream); + for (int i = 0; i < 10; ++i) + header.reserved[i] = IOUtils::ReadBinary<4, int>(stream); + + + if (! stream.good()) + { + m_error = "Error reading model file header"; + return false; + } + + // Old model version #1 + if ( (header.revision == 1) && (header.version == 0) ) + { + for (int i = 0; i < header.totalVertices; ++i) + { + OldModelTriangle1 t; + t.used = IOUtils::ReadBinary<1, char>(stream); + t.selected = IOUtils::ReadBinary<1, char>(stream); + + t.p1 = ReadBinaryVertex(stream); + t.p2 = ReadBinaryVertex(stream); + t.p3 = ReadBinaryVertex(stream); + + t.material = ReadBinaryMaterial(stream); + stream.read(t.texName, 20); + t.min = IOUtils::ReadBinaryFloat(stream); + t.max = IOUtils::ReadBinaryFloat(stream); + + if (! stream.good()) + { + m_error = "Error reading model data"; + return false; + } + + Gfx::ModelTriangle triangle; + triangle.p1.FromVertex(t.p1); + triangle.p2.FromVertex(t.p2); + triangle.p3.FromVertex(t.p3); + + triangle.material = t.material; + triangle.tex1Name = std::string(t.texName); + triangle.min = t.min; + triangle.max = t.max; + + m_triangles.push_back(triangle); + } + } + else if ( header.revision == 1 && header.version == 1 ) + { + for (int i = 0; i < header.totalVertices; ++i) + { + OldModelTriangle2 t; + t.used = IOUtils::ReadBinary<1, char>(stream); + t.selected = IOUtils::ReadBinary<1, char>(stream); + + t.p1 = ReadBinaryVertex(stream); + t.p2 = ReadBinaryVertex(stream); + t.p3 = ReadBinaryVertex(stream); + + t.material = ReadBinaryMaterial(stream); + stream.read(t.texName, 20); + t.min = IOUtils::ReadBinaryFloat(stream); + t.max = IOUtils::ReadBinaryFloat(stream); + t.state = IOUtils::ReadBinary<4, long>(stream); + + t.reserved1 = IOUtils::ReadBinary<2, short>(stream); + t.reserved2 = IOUtils::ReadBinary<2, short>(stream); + t.reserved3 = IOUtils::ReadBinary<2, short>(stream); + t.reserved4 = IOUtils::ReadBinary<2, short>(stream); + + if (! stream.good()) + { + m_error = "Error reading model data"; + return false; + } + + Gfx::ModelTriangle triangle; + triangle.p1.FromVertex(t.p1); + triangle.p2.FromVertex(t.p2); + triangle.p3.FromVertex(t.p3); + + triangle.material = t.material; + triangle.tex1Name = std::string(t.texName); + triangle.min = t.min; + triangle.max = t.max; + triangle.state = t.state; + + m_triangles.push_back(triangle); + } + } + else + { + for (int i = 0; i < header.totalVertices; ++i) + { + NewModelTriangle t; + t.used = IOUtils::ReadBinary<1, char>(stream); + t.selected = IOUtils::ReadBinary<1, char>(stream); + + /* padding */ IOUtils::ReadBinary<2, unsigned int>(stream); + + t.p1 = ReadBinaryVertexTex2(stream); + t.p2 = ReadBinaryVertexTex2(stream); + t.p3 = ReadBinaryVertexTex2(stream); + + t.material = ReadBinaryMaterial(stream); + stream.read(t.texName, 20); + t.min = IOUtils::ReadBinaryFloat(stream); + t.max = IOUtils::ReadBinaryFloat(stream); + t.state = IOUtils::ReadBinary<4, long>(stream); + t.texNum2 = IOUtils::ReadBinary<2, short>(stream); + + t.reserved2 = IOUtils::ReadBinary<2, short>(stream); + t.reserved3 = IOUtils::ReadBinary<2, short>(stream); + t.reserved4 = IOUtils::ReadBinary<2, short>(stream); + + if (! stream.good()) + { + m_error = "Error reading model data"; + return false; + } + + Gfx::ModelTriangle triangle; + triangle.p1 = t.p1; + triangle.p2 = t.p2; + triangle.p3 = t.p3; + + triangle.material = t.material; + triangle.tex1Name = std::string(t.texName); + char tex2Name[20] = { 0 }; + triangle.min = t.min; + triangle.max = t.max; + triangle.state = t.state; + + if (t.texNum2 != 0) + sprintf(tex2Name, "dirty%.2d.tga", t.texNum2); // hardcoded as in the original code + + triangle.tex2Name = std::string(tex2Name); + + m_triangles.push_back(triangle); + } + } + + for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i) + { + m_triangles[i].tex1Name = StrUtils::Replace(m_triangles[i].tex1Name, "bmp", "tga"); + + GetLogger()->Info("ModelTriangle %d\n", i+1); + std::string s1 = m_triangles[i].p1.ToString(); + GetLogger()->Info(" p1: %s\n", s1.c_str()); + std::string s2 = m_triangles[i].p2.ToString(); + GetLogger()->Info(" p2: %s\n", s2.c_str()); + std::string s3 = m_triangles[i].p3.ToString(); + GetLogger()->Info(" p3: %s\n", s3.c_str()); + + std::string d = m_triangles[i].material.diffuse.ToString(); + std::string a = m_triangles[i].material.ambient.ToString(); + std::string s = m_triangles[i].material.specular.ToString(); + GetLogger()->Info(" mat: d: %s a: %s s: %s\n", d.c_str(), a.c_str(), s.c_str()); + + GetLogger()->Info(" tex1: %s tex2: %s\n", m_triangles[i].tex1Name.c_str(), m_triangles[i].tex2Name.c_str()); + GetLogger()->Info(" min: %.2f max: %.2f\n", m_triangles[i].min, m_triangles[i].max); + GetLogger()->Info(" state: %ld\n", m_triangles[i].state); + } + + /* + if (! edit) + { + float limit[2]; + limit[0] = m_engine->RetLimitLOD(0); // frontier AB as config + limit[1] = m_engine->RetLimitLOD(1); // frontier BC as config + + // Standard frontiers -> config. + for (int i = 0; i < m_triangles.size(); ++i) + { + if ( m_triangles[i].min == 0.0f && + m_triangles[i].max == 100.0f ) // resolution A ? + { + m_triangles[i].max = limit[0]; + } + else if ( m_triangles[i].min == 100.0f && + m_triangles[i].max == 200.0f ) // resolution B ? + { + m_triangles[i].min = limit[0]; + m_triangles[i].max = limit[1]; + } + else if ( m_triangles[i].min == 200.0f && + m_triangles[i].max == 1000000.0f ) // resolution C ? + { + m_triangles[i].min = limit[1]; + } + } + }*/ + + return true; +} + +bool Gfx::CModelFile::WriteModel(const std::string &filename) +{ + m_error = ""; + + std::ofstream stream; + stream.open(filename.c_str(), std::ios_base::out | std::ios_base::binary); + if (! stream.good()) + { + m_error = std::string("Could not open file '") + filename + std::string("'"); + return false; + } + + return WriteModel(stream); +} + +bool Gfx::CModelFile::WriteModel(std::ostream &stream) +{ + m_error = ""; + + if (m_triangles.size() == 0) + { + m_error = "Empty model"; + return false; + } + + ModelHeader header; + header.revision = 1; + header.version = 2; + header.totalVertices = m_triangles.size(); + + IOUtils::WriteBinary<4, int>(header.revision, stream); + IOUtils::WriteBinary<4, int>(header.version, stream); + IOUtils::WriteBinary<4, int>(header.totalVertices, stream); + for (int i = 0; i < 10; ++i) + IOUtils::WriteBinary<4, int>(header.reserved[i], stream); + + for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i) + { + NewModelTriangle t; + + t.used = true; + + t.p1 = m_triangles[i].p1; + t.p2 = m_triangles[i].p2; + t.p3 = m_triangles[i].p3; + + t.material = m_triangles[i].material; + strncpy(t.texName, m_triangles[i].tex1Name.c_str(), 20); + t.min = m_triangles[i].min; + t.max = m_triangles[i].max; + t.state = m_triangles[i].state; + int no = 0; + sscanf(m_triangles[i].tex2Name.c_str(), "dirty%d.tga", &no); // hardcoded as in the original code + t.texNum2 = no; + + + IOUtils::WriteBinary<1, char>(t.used, stream); + IOUtils::WriteBinary<1, char>(t.selected, stream); + + WriteBinaryVertexTex2(t.p1, stream); + WriteBinaryVertexTex2(t.p2, stream); + WriteBinaryVertexTex2(t.p3, stream); + + WriteBinaryMaterial(t.material, stream); + stream.write(t.texName, 20); + IOUtils::WriteBinaryFloat(t.min, stream); + IOUtils::WriteBinaryFloat(t.max, stream); + IOUtils::WriteBinary<4, long>(t.state, stream); + IOUtils::WriteBinary<2, short>(t.texNum2, stream); + + IOUtils::WriteBinary<2, short>(t.reserved2, stream); + IOUtils::WriteBinary<2, short>(t.reserved3, stream); + IOUtils::WriteBinary<2, short>(t.reserved4, stream); + } + + return true; +} + +bool Gfx::CModelFile::ReadDXF(const std::string &filename, float min, float max) +{ + m_triangles.clear(); + m_error = ""; + + std::ifstream stream; + stream.open(filename.c_str(), std::ios_base::in); + if (! stream.good()) + { + m_error = std::string("Couldn't open file '") + filename + std::string("'"); + return false; + } + + return ReadDXF(stream, min, max); +} + +bool Gfx::CModelFile::ReadDXF(std::istream &stream, float min, float max) +{ + m_triangles.clear(); + m_error = ""; + + if (! stream.good()) + { + m_error = "Invalid stream"; + return false; + } + + // Input state + bool waitNumVertex = false; + bool waitNumFace = false; + bool waitVertexX = false; + bool waitVertexY = false; + bool waitVertexZ = false; + bool waitFaceX = false; + bool waitFaceY = false; + bool waitFaceZ = false; + + // Vertex array + std::vector<Math::Vector> vertices; + vertices.reserve(TRIANGLE_PREALLOCATE_COUNT); + + // Number of vertices & faces of the primitive to be read + int vertexNum = 0, faceNum = 0; + // Vertex coords + Math::Vector coords; + // Indexes of face (triangle) points + int p1 = 0, p2 = 0, p3 = 0; + + // Input line + std::string line; + while (! stream.eof() ) + { + // Read line with command + std::getline(stream, line); + int command = StrUtils::FromString<int>(line); + + // Read line with param + std::getline(stream, line); + + bool ok = true; + + + if (command == 66) + { + waitNumVertex = true; + } + + if ( command == 71 && waitNumVertex ) + { + waitNumVertex = false; + vertexNum = StrUtils::FromString<int>(line, &ok); + waitNumFace = true; + } + + if ( command == 72 && waitNumFace ) + { + waitNumFace = false; + faceNum = StrUtils::FromString<int>(line, &ok); + waitVertexX = true; + } + + if ( command == 10 && waitVertexX ) + { + waitVertexX = false; + coords.x = StrUtils::FromString<float>(line, &ok); + waitVertexY = true; + } + + if ( command == 20 && waitVertexY ) + { + waitVertexY = false; + coords.y = StrUtils::FromString<float>(line, &ok); + waitVertexZ = true; + } + + if ( command == 30 && waitVertexZ ) + { + waitVertexZ = false; + coords.z = StrUtils::FromString<float>(line, &ok); + + vertexNum --; + if ( vertexNum >= 0 ) + { + Math::Vector p(coords.x, coords.z, coords.y); // permutation of Y and Z! + vertices.push_back(p); + waitVertexX = true; + } + else + { + waitFaceX = true; + } + } + + if ( command == 71 && waitFaceX ) + { + waitFaceX = false; + p1 = StrUtils::FromString<int>(line, &ok); + if ( p1 < 0 ) p1 = -p1; + waitFaceY = true; + } + + if ( command == 72 && waitFaceY ) + { + waitFaceY = false; + p2 = StrUtils::FromString<int>(line, &ok); + if ( p2 < 0 ) p2 = -p2; + waitFaceZ = true; + } + + if ( command == 73 && waitFaceZ ) + { + waitFaceZ = false; + p3 = StrUtils::FromString<int>(line, &ok); + if ( p3 < 0 ) p3 = -p3; + + faceNum --; + if ( faceNum >= 0 ) + { + assert( (p1-1 >= 0) && (p1-1 < static_cast<int>(vertices.size())) ); + assert( (p2-1 >= 0) && (p2-1 < static_cast<int>(vertices.size())) ); + assert( (p3-1 >= 0) && (p3-1 < static_cast<int>(vertices.size())) ); + + CreateTriangle(vertices[p3-1], vertices[p2-1], vertices[p1-1], min, max); + waitFaceX = true; + } + } + + if (! ok) + { + m_error = "Error reading data"; + return false; + } + + } + + return true; +} + +bool Gfx::CModelFile::CreateEngineObject(int objRank, int addState) +{ + /*char texName1[20]; + char texName2[20]; + int texNum, i, state; + + for (int i = 0; i < m_trianglesUsed; i++) + { + if (! m_triangles[i].used) continue; + + state = m_triangles[i].state; + strcpy(texName1, m_triangles[i].texName); + texName2[0] = 0; + + if ( strcmp(texName1, "plant.tga") == 0 ) // ??? + { + state |= D3DSTATEALPHA; + } + + if ( m_triangles[i].texNum2 != 0 ) + { + if ( m_triangles[i].texNum2 == 1 ) + { + texNum = m_engine->RetSecondTexture(); + } + else + { + texNum = m_triangles[i].texNum2; + } + + if ( texNum >= 1 && texNum <= 10 ) + { + state |= D3DSTATEDUALb; + } + if ( texNum >= 11 && texNum <= 20 ) + { + state |= D3DSTATEDUALw; + } + sprintf(texName2, "dirty%.2d.tga", texNum); // ??? + } + + m_engine->AddTriangle(objRank, &m_triangles[i].p1, 3, + m_triangles[i].material, + state + addState, + texName1, texName2, + m_triangles[i].min, + m_triangles[i].max, false); + }*/ + return true; +} + +void Gfx::CModelFile::Mirror() +{ + for (int i = 0; i < static_cast<int>( m_triangles.size() ); i++) + { + Gfx::VertexTex2 t = m_triangles[i].p1; + m_triangles[i].p1 = m_triangles[i].p2; + m_triangles[i].p2 = t; + + m_triangles[i].p1.coord.z = -m_triangles[i].p1.coord.z; + m_triangles[i].p2.coord.z = -m_triangles[i].p2.coord.z; + m_triangles[i].p3.coord.z = -m_triangles[i].p3.coord.z; + + m_triangles[i].p1.normal.z = -m_triangles[i].p1.normal.z; + m_triangles[i].p2.normal.z = -m_triangles[i].p2.normal.z; + m_triangles[i].p3.normal.z = -m_triangles[i].p3.normal.z; + } +} + +std::vector<Gfx::ModelTriangle>& Gfx::CModelFile::GetTriangles() +{ + return m_triangles; +} + +int Gfx::CModelFile::GetTriangleCount() +{ + return m_triangles.size(); +} + +float Gfx::CModelFile::GetHeight(Math::Vector pos) +{ + float limit = 5.0f; + + for (int i = 0; i < static_cast<int>( m_triangles.size() ); i++) + { + if ( fabs(pos.x - m_triangles[i].p1.coord.x) < limit && + fabs(pos.z - m_triangles[i].p1.coord.z) < limit ) + return m_triangles[i].p1.coord.y; + + if ( fabs(pos.x - m_triangles[i].p2.coord.x) < limit && + fabs(pos.z - m_triangles[i].p2.coord.z) < limit ) + return m_triangles[i].p2.coord.y; + + if ( fabs(pos.x - m_triangles[i].p3.coord.x) < limit && + fabs(pos.z - m_triangles[i].p3.coord.z) < limit ) + return m_triangles[i].p3.coord.y; + } + + return 0.0f; +} + +void Gfx::CModelFile::CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max) +{ + Gfx::ModelTriangle triangle; + + Math::Vector n = Math::NormalToPlane(p3, p2, p1); + triangle.p1 = Gfx::VertexTex2(p1, n); + triangle.p2 = Gfx::VertexTex2(p2, n); + triangle.p3 = Gfx::VertexTex2(p3, n); + + triangle.material.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f, 0.0f); + triangle.material.ambient = Gfx::Color(0.5f, 0.5f, 0.5f, 0.0f); + + triangle.min = min; + triangle.max = max; + + m_triangles.push_back(triangle); +} diff --git a/src/graphics/engine/modelfile.h b/src/graphics/engine/modelfile.h new file mode 100644 index 0000000..6a30487 --- /dev/null +++ b/src/graphics/engine/modelfile.h @@ -0,0 +1,120 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * 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/. + +// modelfile.h (aka modfile.h) + +#include "graphics/engine/engine.h" +#include "graphics/core/vertex.h" +#include "graphics/core/material.h" +#include "math/vector.h" + +#include <string> +#include <vector> +#include <iostream> + + +class CInstanceManager; + + +namespace Gfx { + +/** + \struct ModelTriangle + \brief Triangle of a 3D model + */ +struct ModelTriangle +{ + //! 1st vertex + Gfx::VertexTex2 p1; + //! 2nd vertex + Gfx::VertexTex2 p2; + //! 3rd vertex + Gfx::VertexTex2 p3; + //! Material + Gfx::Material material; + //! Name of 1st texture + std::string tex1Name; + //! Name of 2nd texture + std::string tex2Name; + //! Min LOD threshold + float min; + //! Max LOD threshold + float max; + //! Rendering state to be set + long state; + + ModelTriangle(); +}; + + +/** + \class CModelFile + \brief Model file reader/writer + + Allows reading and writing model objects. Models are collections of ModelTriangle structs. */ +class CModelFile +{ +public: + CModelFile(CInstanceManager* iMan); + ~CModelFile(); + + //! Returns the last error encountered + std::string GetError(); + + //! Reads a binary Colobot model from file + bool ReadModel(const std::string &filename, bool edit = false, bool meta = true); + //! Reads a binary Colobot model from stream + bool ReadModel(std::istream &stream, bool edit = false, bool meta = true); + //! Writes the model to Colobot binary model file + bool WriteModel(const std::string &filename); + //! Writes the model to Colobot binary model file + bool WriteModel(std::ostream &stream); + + //! Reads a DXF model from file + bool ReadDXF(const std::string &filename, float min, float max); + //! Reads a DXF model from stream + bool ReadDXF(std::istream &stream, float min, float max); + + //! Returns the number of triangles in model + int GetTriangleCount(); + //! Returns the triangle vector + std::vector<Gfx::ModelTriangle>& GetTriangles(); + //! Returns the height of model -- closest point to X and Z coords of \a pos + float GetHeight(Math::Vector pos); + + //! Mirrors the model along the Z axis + void Mirror(); + + //! Creates an object in the graphics engine from the model + bool CreateEngineObject(int objRank, int addState = 0); + +protected: + //! Adds a triangle to the list + void CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max); + +protected: + CInstanceManager* m_iMan; + Gfx::CEngine* m_engine; + + //! Last error + std::string m_error; + + //! Model triangles + std::vector<Gfx::ModelTriangle> m_triangles; +}; + +}; // namespace Gfx diff --git a/src/graphics/common/particle.cpp b/src/graphics/engine/particle.cpp index 322c2d0..84e2f9d 100644 --- a/src/graphics/common/particle.cpp +++ b/src/graphics/engine/particle.cpp @@ -17,7 +17,7 @@ // particle.cpp (aka particule.cpp) -#include "graphics/common/particle.h" +#include "graphics/engine/particle.h" // TODO implementation diff --git a/src/graphics/common/particle.h b/src/graphics/engine/particle.h index e430e2a..bd9741f 100644 --- a/src/graphics/common/particle.h +++ b/src/graphics/engine/particle.h @@ -25,9 +25,8 @@ class CInstanceManager; class CRobotMain; -class Gfx::CTerrain; -class Gfx::CWater; class CObject; +class CSound; @@ -52,7 +51,7 @@ const short SH_MAX = 3; // type == 4 -> text (white background) -enum ParticuleType +enum ParticleType { PARTIEXPLOT = 1, // technology explosion PARTIEXPLOO = 2, // organic explosion @@ -195,20 +194,20 @@ enum ParticuleType PARTITRACE19 = 159, // trace }; -enum ParticulePhase +enum ParticlePhase { PARPHSTART = 0, PARPHEND = 1, }; -struct Particule +struct Particle { char bUsed; // TRUE -> particle used char bRay; // TRUE -> ray with goal unsigned short uniqueStamp; // unique mark short sheet; // sheet (0..n) - ParticuleType type; // type PARTI* - ParticulePhase phase; // phase PARPH* + ParticleType type; // type PARTI* + ParticlePhase phase; // phase PARPH* float mass; // mass of the particle (in rebounding) float weight; // weight of the particle (for noise) float duration; // length of life @@ -235,7 +234,7 @@ struct Particule struct Track { char bUsed; // TRUE -> drag used - char bDrawParticule; + char bDrawParticle; float step; // duration of not float last; // increase last not memorized float intensity; // intensity at starting (0..1) @@ -248,7 +247,7 @@ struct Track struct WheelTrace { - ParticuleType type; // type PARTI* + ParticleType type; // type PARTI* Math::Vector pos[4]; // rectangle positions float startTime; // beginning of life }; @@ -263,16 +262,16 @@ public: void SetGLDevice(CDevice device); - void FlushParticule(); - void FlushParticule(int sheet); - int CreateParticule(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0); - int CreateFrag(Math::Vector pos, Math::Vector speed, Triangle *triangle, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0); - int CreatePart(Math::Vector pos, Math::Vector speed, ParticuleType type, float duration=1.0f, float mass=0.0f, float weight=0.0f, float windSensitivity=1.0f, int sheet=0); - int CreateRay(Math::Vector pos, Math::Vector goal, ParticuleType type, Math::Point dim, float duration=1.0f, int sheet=0); - int CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float length=10.0f, float width=1.0f); - void CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3, const Math::Vector &p4, ParticuleType type); - void DeleteParticule(ParticuleType type); - void DeleteParticule(int channel); + void FlushParticle(); + void FlushParticle(int sheet); + int CreateParticle(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0); + int CreateFrag(Math::Vector pos, Math::Vector speed, Gfx::EngineTriangle *triangle, ParticleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0); + int CreatePart(Math::Vector pos, Math::Vector speed, ParticleType type, float duration=1.0f, float mass=0.0f, float weight=0.0f, float windSensitivity=1.0f, int sheet=0); + int CreateRay(Math::Vector pos, Math::Vector goal, ParticleType type, Math::Point dim, float duration=1.0f, int sheet=0); + int CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type, float duration=1.0f, float mass=0.0f, float length=10.0f, float width=1.0f); + void CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3, const Math::Vector &p4, ParticleType type); + void DeleteParticle(ParticleType type); + void DeleteParticle(int channel); void SetObjectLink(int channel, CObject *object); void SetObjectFather(int channel, CObject *object); void SetPosition(int channel, Math::Vector pos); @@ -281,57 +280,57 @@ public: void SetAngle(int channel, float angle); void SetIntensity(int channel, float intensity); void SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity); - void SetPhase(int channel, ParticulePhase phase, float duration); + void SetPhase(int channel, ParticlePhase phase, float duration); bool GetPosition(int channel, Math::Vector &pos); Gfx::Color RetFogColor(Math::Vector pos); void SetFrameUpdate(int sheet, bool bUpdate); - void FrameParticule(float rTime); - void DrawParticule(int sheet); + void FrameParticle(float rTime); + void DrawParticle(int sheet); bool WriteWheelTrace(char *filename, int width, int height, Math::Vector dl, Math::Vector ur); protected: void DeleteRank(int rank); bool CheckChannel(int &channel); - void DrawParticuleTriangle(int i); - void DrawParticuleNorm(int i); - void DrawParticuleFlat(int i); - void DrawParticuleFog(int i); - void DrawParticuleRay(int i); - void DrawParticuleSphere(int i); - void DrawParticuleCylinder(int i); - void DrawParticuleWheel(int i); - CObject* SearchObjectGun(Math::Vector old, Math::Vector pos, ParticuleType type, CObject *father); - CObject* SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticuleType type, CObject *father); - void Play(Snd::Sound sound, Math::Vector pos, float amplitude); + void DrawParticleTriangle(int i); + void DrawParticleNorm(int i); + void DrawParticleFlat(int i); + void DrawParticleFog(int i); + void DrawParticleRay(int i); + void DrawParticleSphere(int i); + void DrawParticleCylinder(int i); + void DrawParticleWheel(int i); + CObject* SearchObjectGun(Math::Vector old, Math::Vector pos, ParticleType type, CObject *father); + CObject* SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticleType type, CObject *father); + void Play(Sound sound, Math::Vector pos, float amplitude); bool TrackMove(int i, Math::Vector pos, float progress); - void TrackDraw(int i, ParticuleType type); + void TrackDraw(int i, ParticleType type); protected: - CInstanceManager* m_iMan; - CEngine* m_engine; - CDevice* m_pDevice; - CRobotMain* m_main; - CTerrain* m_terrain; - CWater* m_water; - CSound* m_sound; + CInstanceManager* m_iMan; + CEngine* m_engine; + CDevice* m_pDevice; + CRobotMain* m_main; + CTerrain* m_terrain; + CWater* m_water; + CSound* m_sound; - Particule m_particule[MAXPARTICULE*MAXPARTITYPE]; - Gfx::Triangle m_triangle[MAXPARTICULE]; // triangle if PartiType == 0 - Track m_track[MAXTRACK]; - int m_wheelTraceTotal; - int m_wheelTraceIndex; - WheelTrace m_wheelTrace[MAXWHEELTRACE]; - int m_totalInterface[MAXPARTITYPE][SH_MAX]; - bool m_bFrameUpdate[SH_MAX]; - int m_fogTotal; - int m_fog[MAXPARTIFOG]; - int m_uniqueStamp; - int m_exploGunCounter; - float m_lastTimeGunDel; - float m_absTime; + Gfx::Particle m_particule[MAXPARTICULE*MAXPARTITYPE]; + Gfx::EngineTriangle m_triangle[MAXPARTICULE]; // triangle if PartiType == 0 + Track m_track[MAXTRACK]; + int m_wheelTraceTotal; + int m_wheelTraceIndex; + WheelTrace m_wheelTrace[MAXWHEELTRACE]; + int m_totalInterface[MAXPARTITYPE][SH_MAX]; + bool m_bFrameUpdate[SH_MAX]; + int m_fogTotal; + int m_fog[MAXPARTIFOG]; + int m_uniqueStamp; + int m_exploGunCounter; + float m_lastTimeGunDel; + float m_absTime; }; diff --git a/src/graphics/common/planet.cpp b/src/graphics/engine/planet.cpp index 4fa17a1..4f1f614 100644 --- a/src/graphics/common/planet.cpp +++ b/src/graphics/engine/planet.cpp @@ -17,7 +17,7 @@ // planet.cpp -#include "graphics/common/planet.h" +#include "graphics/engine/planet.h" // TODO implementation diff --git a/src/graphics/common/planet.h b/src/graphics/engine/planet.h index 264d05c..264d05c 100644 --- a/src/graphics/common/planet.h +++ b/src/graphics/engine/planet.h diff --git a/src/graphics/common/pyro.cpp b/src/graphics/engine/pyro.cpp index 6b5b1af..e699db2 100644 --- a/src/graphics/common/pyro.cpp +++ b/src/graphics/engine/pyro.cpp @@ -17,7 +17,7 @@ // pyro.cpp -#include "graphics/common/pyro.h" +#include "graphics/engine/pyro.h" // TODO implementation diff --git a/src/graphics/common/pyro.h b/src/graphics/engine/pyro.h index fda74b3..d663ca5 100644 --- a/src/graphics/common/pyro.h +++ b/src/graphics/engine/pyro.h @@ -20,7 +20,7 @@ #pragma once #include "common/misc.h" -#include "graphics/common/engine.h" +#include "graphics/engine/engine.h" //#include "object/object.h" // TEMPORARILY! enum ObjectType {}; diff --git a/src/graphics/common/terrain.cpp b/src/graphics/engine/terrain.cpp index 9b61dfc..c489321 100644 --- a/src/graphics/common/terrain.cpp +++ b/src/graphics/engine/terrain.cpp @@ -17,7 +17,7 @@ // terrain.cpp -#include "graphics/common/terrain.h" +#include "graphics/engine/terrain.h" // TODO implementation diff --git a/src/graphics/common/terrain.h b/src/graphics/engine/terrain.h index fd9a1a6..8d8b165 100644 --- a/src/graphics/common/terrain.h +++ b/src/graphics/engine/terrain.h @@ -19,7 +19,7 @@ #pragma once -#include "graphics/common/engine.h" +#include "graphics/engine/engine.h" class CInstanceManager; diff --git a/src/graphics/engine/test/CMakeLists.txt b/src/graphics/engine/test/CMakeLists.txt new file mode 100644 index 0000000..bd83773 --- /dev/null +++ b/src/graphics/engine/test/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8) + +set(CMAKE_BUILD_TYPE debug) +set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0") + +include_directories(. ../../..) +add_executable(modelfile_test modelfile_test.cpp ../modelfile.cpp ../../../common/logger.cpp ../../../common/stringutils.cpp ../../../common/iman.cpp) diff --git a/src/graphics/engine/test/modelfile_test.cpp b/src/graphics/engine/test/modelfile_test.cpp new file mode 100644 index 0000000..f7ed87f --- /dev/null +++ b/src/graphics/engine/test/modelfile_test.cpp @@ -0,0 +1,48 @@ +#include "graphics/engine/modelfile.h" +#include "common/iman.h" + +#include <iostream> + + +int main(int argc, char *argv[]) +{ + if (argc != 4) + { + std::cerr << "Usage: " << argv[0] << " {mod|dxf} in_file out_file" << std::endl; + return 1; + } + + CInstanceManager iMan; + Gfx::CModelFile modfile(&iMan); + + std::string mode(argv[1]); + if (mode == "mod") + { + if (! modfile.ReadModel(argv[2], false, false) ) + { + std::cerr << "Read error: " << modfile.GetError() << std::endl; + return 2; + } + } + else if (mode == "dxf") + { + if (! modfile.ReadDXF(argv[2], false, false) ) + { + std::cerr << "Read error: " << modfile.GetError() << std::endl; + return 2; + } + } + else + { + std::cerr << "Usage: " << argv[0] << " {mod|dxf} in_file out_file" << std::endl; + return 1; + } + + if (! modfile.WriteModel(argv[3]) ) + { + std::cerr << "Write error: " << modfile.GetError() << std::endl; + return 3; + } + + return 0; +} diff --git a/src/graphics/common/text.cpp b/src/graphics/engine/text.cpp index 0c5eb66..2a9543c 100644 --- a/src/graphics/common/text.cpp +++ b/src/graphics/engine/text.cpp @@ -17,7 +17,7 @@ // text.cpp -#include "graphics/common/text.h" +#include "graphics/engine/text.h" // TODO implementation diff --git a/src/graphics/common/text.h b/src/graphics/engine/text.h index 00b73f2..c2de220 100644 --- a/src/graphics/common/text.h +++ b/src/graphics/engine/text.h @@ -19,8 +19,8 @@ #pragma once -#include "graphics/common/engine.h" -#include "graphics/common/device.h" +#include "graphics/engine/engine.h" +#include "graphics/core/device.h" #include "math/point.h" @@ -73,7 +73,7 @@ public: CText(CInstanceManager *iMan, Gfx::CEngine* engine); ~CText(); - void SetGLDevice(Gfx::CDevice device); + void SetDevice(Gfx::CDevice *device); void DrawText(char *string, char *format, int len, Math::Point pos, float width, int justif, float size, float stretch, int eol); void DrawText(char *string, char *format, Math::Point pos, float width, int justif, float size, float stretch, int eol); @@ -106,7 +106,7 @@ protected: protected: CInstanceManager* m_iMan; Gfx::CEngine* m_engine; - Gfx::CDevice m_pDevice; + Gfx::CDevice* m_device; }; diff --git a/src/graphics/common/water.cpp b/src/graphics/engine/water.cpp index 5172b9f..a157e82 100644 --- a/src/graphics/common/water.cpp +++ b/src/graphics/engine/water.cpp @@ -17,7 +17,7 @@ // water.cpp -#include "graphics/common/water.h" +#include "graphics/engine/water.h" // TODO implementation diff --git a/src/graphics/common/water.h b/src/graphics/engine/water.h index 5999eac..67be9dc 100644 --- a/src/graphics/common/water.h +++ b/src/graphics/engine/water.h @@ -19,8 +19,8 @@ #pragma once -#include "graphics/common/engine.h" -#include "graphics/common/particle.h" +#include "graphics/engine/engine.h" +#include "graphics/engine/particle.h" #include "common/event.h" @@ -48,7 +48,7 @@ const short MAXWATVAPOR = 10; struct WaterVapor { bool bUsed; - ParticuleType type; + ParticleType type; Math::Vector pos; float delay; float time; @@ -96,7 +96,7 @@ protected: bool CreateLine(int x, int y, int len); void VaporFlush(); - bool VaporCreate(ParticuleType type, Math::Vector pos, float delay); + bool VaporCreate(ParticleType type, Math::Vector pos, float delay); void VaporFrame(int i, float rTime); protected: diff --git a/src/graphics/opengl/README.txt b/src/graphics/opengl/README.txt index 11aba8d..0aba0ed 100644 --- a/src/graphics/opengl/README.txt +++ b/src/graphics/opengl/README.txt @@ -2,5 +2,5 @@ src/graphics/opengl OpenGL engine implementation -Contains the concreate implementation using OpenGL of functions -of grahpics engine in graphics/common. +Contains the concrete implementation using OpenGL of abstract CDevice class +from src/graphics/core diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp index 7938e62..3a255f4 100644 --- a/src/graphics/opengl/gldevice.cpp +++ b/src/graphics/opengl/gldevice.cpp @@ -18,4 +18,1194 @@ #include "graphics/opengl/gldevice.h" -// TODO +#include "common/config.h" +#include "common/image.h" +#include "math/geometry.h" + + +#if defined(USE_GLEW) + +// When using GLEW, only glew.h is needed +#include <GL/glew.h> + +#else + +// Should define prototypes of used extensions as OpenGL functions +#define GL_GLEXT_PROTOTYPES + +#include <GL/gl.h> +#include <GL/glu.h> +#include <GL/glext.h> + +#endif // if defined(GLEW) + +#include <SDL/SDL.h> + +#include <cassert> + + + +void Gfx::GLDeviceConfig::LoadDefault() +{ + Gfx::DeviceConfig::LoadDefault(); + + hardwareAccel = true; + + redSize = 8; + blueSize = 8; + greenSize = 8; + alphaSize = 8; + depthSize = 24; +} + + + + +Gfx::CGLDevice::CGLDevice(const Gfx::GLDeviceConfig &config) +{ + m_config = config; + m_wasInit = false; + m_lighting = false; + m_texturing = false; +} + + +Gfx::CGLDevice::~CGLDevice() +{ +} + +bool Gfx::CGLDevice::GetWasInit() +{ + return m_wasInit; +} + +std::string Gfx::CGLDevice::GetError() +{ + return m_error; +} + +bool Gfx::CGLDevice::Create() +{ +#if defined(USE_GLEW) + static bool glewInited = false; + + if (!glewInited) + { + glewInited = true; + + if (glewInit() != GLEW_OK) + { + m_error = "GLEW initialization failed"; + return false; + } + + if ( (! GLEW_ARB_multitexture) || (! GLEW_EXT_texture_env_combine) || (! GLEW_EXT_secondary_color) ) + { + m_error = "GLEW reports required extensions not supported"; + return false; + } + } +#endif + + /* NOTE: when not using GLEW, extension testing is not performed, as it is assumed that + glext.h is up-to-date and the OpenGL shared library has the required functions present. */ + + 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); + + // To use separate specular color in drawing primitives + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); + + // To avoid problems with scaling & lighting + glEnable(GL_RESCALE_NORMAL); + + // Set just to be sure + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glViewport(0, 0, m_config.size.w, m_config.size.h); + + + m_lights = std::vector<Gfx::Light>(GL_MAX_LIGHTS, Gfx::Light()); + m_lightsEnabled = std::vector<bool> (GL_MAX_LIGHTS, false); + + int maxTextures = 0; + glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextures); + + m_currentTextures = std::vector<Gfx::Texture> (maxTextures, Gfx::Texture()); + m_texturesEnabled = std::vector<bool> (maxTextures, false); + m_textureStageParams = std::vector<Gfx::TextureStageParams>(maxTextures, Gfx::TextureStageParams()); + + return true; +} + +void Gfx::CGLDevice::Destroy() +{ + // Delete the remaining textures + // Should not be strictly necessary, but just in case + DestroyAllTextures(); + + m_lights.clear(); + m_lightsEnabled.clear(); + + m_currentTextures.clear(); + m_texturesEnabled.clear(); + m_textureStageParams.clear(); + + m_wasInit = false; +} + +void Gfx::CGLDevice::ConfigChanged(const Gfx::GLDeviceConfig& newConfig) +{ + m_config = newConfig; + + // Reset state + m_lighting = false; + m_texturing = false; + Destroy(); + Create(); +} + +void Gfx::CGLDevice::BeginScene() +{ + Clear(); + + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(m_projectionMat.Array()); + + UpdateModelviewMatrix(); +} + +void Gfx::CGLDevice::EndScene() +{ + glFlush(); +} + +void Gfx::CGLDevice::Clear() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void Gfx::CGLDevice::SetTransform(Gfx::TransformType type, const Math::Matrix &matrix) +{ + if (type == Gfx::TRANSFORM_WORLD) + { + m_worldMat = matrix; + UpdateModelviewMatrix(); + } + else if (type == Gfx::TRANSFORM_VIEW) + { + m_viewMat = matrix; + UpdateModelviewMatrix(); + } + else if (type == Gfx::TRANSFORM_PROJECTION) + { + m_projectionMat = matrix; + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(m_projectionMat.Array()); + } + else + { + assert(false); + } +} + +const Math::Matrix& Gfx::CGLDevice::GetTransform(Gfx::TransformType type) +{ + if (type == Gfx::TRANSFORM_WORLD) + return m_worldMat; + else if (type == Gfx::TRANSFORM_VIEW) + return m_viewMat; + else if (type == Gfx::TRANSFORM_PROJECTION) + return m_projectionMat; + else + assert(false); + + return m_worldMat; // to avoid warning +} + +void Gfx::CGLDevice::MultiplyTransform(Gfx::TransformType type, const Math::Matrix &matrix) +{ + if (type == Gfx::TRANSFORM_WORLD) + { + m_worldMat = Math::MultiplyMatrices(m_worldMat, matrix); + UpdateModelviewMatrix(); + } + else if (type == Gfx::TRANSFORM_VIEW) + { + m_viewMat = Math::MultiplyMatrices(m_viewMat, matrix); + UpdateModelviewMatrix(); + } + else if (type == Gfx::TRANSFORM_PROJECTION) + { + m_projectionMat = Math::MultiplyMatrices(m_projectionMat, matrix); + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(m_projectionMat.Array()); + } + else + { + assert(false); + } +} + +void Gfx::CGLDevice::UpdateModelviewMatrix() +{ + m_modelviewMat = Math::MultiplyMatrices(m_viewMat, m_worldMat); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glScalef(1.0f, 1.0f, -1.0f); + glMultMatrixf(m_modelviewMat.Array()); + + if (m_lighting) + { + for (int index = 0; index < static_cast<int>( m_lights.size() ); ++index) + UpdateLightPosition(index); + } +} + +void Gfx::CGLDevice::SetMaterial(const Gfx::Material &material) +{ + m_material = material; + + glMaterialfv(GL_FRONT, GL_AMBIENT, m_material.ambient.Array()); + glMaterialfv(GL_FRONT, GL_DIFFUSE, m_material.diffuse.Array()); + glMaterialfv(GL_FRONT, GL_SPECULAR, m_material.specular.Array()); +} + +const Gfx::Material& Gfx::CGLDevice::GetMaterial() +{ + return m_material; +} + +int Gfx::CGLDevice::GetMaxLightCount() +{ + return m_lights.size(); +} + +void Gfx::CGLDevice::SetLight(int index, const Gfx::Light &light) +{ + assert(index >= 0); + assert(index < static_cast<int>( m_lights.size() )); + + m_lights[index] = light; + + // Indexing from GL_LIGHT0 should always work + glLightfv(GL_LIGHT0 + index, GL_AMBIENT, const_cast<GLfloat*>(light.ambient.Array())); + glLightfv(GL_LIGHT0 + index, GL_DIFFUSE, const_cast<GLfloat*>(light.diffuse.Array())); + glLightfv(GL_LIGHT0 + index, GL_SPECULAR, const_cast<GLfloat*>(light.specular.Array())); + + glLightf(GL_LIGHT0 + index, GL_CONSTANT_ATTENUATION, light.attenuation0); + glLightf(GL_LIGHT0 + index, GL_LINEAR_ATTENUATION, light.attenuation1); + glLightf(GL_LIGHT0 + index, GL_QUADRATIC_ATTENUATION, light.attenuation2); + + if (light.type == Gfx::LIGHT_SPOT) + { + glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, light.spotAngle); + glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, light.spotIntensity); + } + else + { + glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, 180.0f); + } + + UpdateLightPosition(index); +} + +void Gfx::CGLDevice::UpdateLightPosition(int index) +{ + assert(index >= 0); + assert(index < static_cast<int>( m_lights.size() )); + + if ((! m_lighting) || (! m_lightsEnabled[index])) + return; + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + glLoadIdentity(); + glScalef(1.0f, 1.0f, -1.0f); + glMultMatrixf(m_viewMat.Array()); + + if (m_lights[index].type == LIGHT_DIRECTIONAL) + { + GLfloat position[4] = { m_lights[index].direction.x, m_lights[index].direction.y, m_lights[index].direction.z, 0.0f }; + glLightfv(GL_LIGHT0 + index, GL_POSITION, position); + } + else + { + GLfloat position[4] = { m_lights[index].position.x, m_lights[index].position.y, m_lights[index].position.z, 1.0f }; + glLightfv(GL_LIGHT0 + index, GL_POSITION, position); + } + + if (m_lights[index].type == Gfx::LIGHT_SPOT) + { + GLfloat direction[4] = { m_lights[index].direction.x, m_lights[index].direction.y, m_lights[index].direction.z, 0.0f }; + glLightfv(GL_LIGHT0 + index, GL_SPOT_DIRECTION, direction); + } + + glPopMatrix(); +} + +const Gfx::Light& Gfx::CGLDevice::GetLight(int index) +{ + assert(index >= 0); + assert(index < static_cast<int>( m_lights.size() )); + + return m_lights[index]; +} + +void Gfx::CGLDevice::SetLightEnabled(int index, bool enabled) +{ + assert(index >= 0); + assert(index < static_cast<int>( m_lights.size() )); + + m_lightsEnabled[index] = enabled; + + glEnable(GL_LIGHT0 + index); +} + +bool Gfx::CGLDevice::GetLightEnabled(int index) +{ + assert(index >= 0); + assert(index < static_cast<int>( m_lights.size() )); + + return m_lightsEnabled[index]; +} + +/** If image is invalid, returns invalid texture. + Otherwise, returns pointer to new Gfx::Texture struct. + This struct must not be deleted in other way than through DeleteTexture() */ +Gfx::Texture Gfx::CGLDevice::CreateTexture(CImage *image, const Gfx::TextureCreateParams ¶ms) +{ + Gfx::Texture result; + + ImageData *data = image->GetData(); + if (data == NULL) + { + m_error = "Invalid texture data"; + return result; // invalid texture + } + + result.valid = true; + result.size.w = data->surface->w; + result.size.h = data->surface->h; + + // Use & enable 1st texture stage + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_2D); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glGenTextures(1, &result.id); + glBindTexture(GL_TEXTURE_2D, result.id); + + // Set params + + 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.mipmap) + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + else + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); + + GLenum sourceFormat = 0; + if (params.format == Gfx::TEX_IMG_RGB) + { + sourceFormat = GL_RGB; + result.alpha = false; + } + else if (params.format == Gfx::TEX_IMG_BGR) + { + sourceFormat = GL_BGR; + result.alpha = false; + } + else if (params.format == Gfx::TEX_IMG_RGBA) + { + sourceFormat = GL_RGBA; + result.alpha = true; + } + else if (params.format == Gfx::TEX_IMG_BGRA) + { + sourceFormat = GL_BGRA; + result.alpha = true; + } + else + assert(false); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data->surface->w, data->surface->h, + 0, sourceFormat, GL_UNSIGNED_BYTE, data->surface->pixels); + + + // Restore the previous state of 1st stage + if (m_currentTextures[0].valid) + glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); + else + glBindTexture(GL_TEXTURE_2D, 0); + + if ( (! m_texturing) || (! m_texturesEnabled[0]) ) + glDisable(GL_TEXTURE_2D); + + return result; +} + +void Gfx::CGLDevice::DestroyTexture(const Gfx::Texture &texture) +{ + std::set<Gfx::Texture>::iterator it = m_allTextures.find(texture); + if (it != m_allTextures.end()) + m_allTextures.erase(it); + + // Unbind the texture if in use anywhere + for (int index = 0; index < static_cast<int>( m_currentTextures.size() ); ++index) + { + if (m_currentTextures[index] == texture) + SetTexture(index, Gfx::Texture()); // set to invalid texture + } + + glDeleteTextures(1, &texture.id); +} + +void Gfx::CGLDevice::DestroyAllTextures() +{ + std::set<Gfx::Texture> allCopy = m_allTextures; + std::set<Gfx::Texture>::iterator it; + for (it = allCopy.begin(); it != allCopy.end(); ++it) + DestroyTexture(*it); +} + +int Gfx::CGLDevice::GetMaxTextureCount() +{ + return m_currentTextures.size(); +} + +/** + If \a texture is 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, const Gfx::Texture &texture) +{ + assert(index >= 0); + assert(index < static_cast<int>( m_currentTextures.size() )); + + // Enable the given texture stage + glActiveTexture(GL_TEXTURE0 + index); + glEnable(GL_TEXTURE_2D); + + m_currentTextures[index] = texture; // remember the change + + if (! texture.valid) + { + glBindTexture(GL_TEXTURE_2D, 0); // unbind texture + } + else + { + glBindTexture(GL_TEXTURE_2D, texture.id); // bind the texture + SetTextureStageParams(index, m_textureStageParams[index]); // texture stage 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 invalid texture if the given stage is not enabled. */ +Gfx::Texture Gfx::CGLDevice::GetTexture(int index) +{ + assert(index >= 0); + assert(index < static_cast<int>( m_currentTextures.size() )); + + return m_currentTextures[index]; +} + +void Gfx::CGLDevice::SetTextureEnabled(int index, bool enabled) +{ + assert(index >= 0); + assert(index < static_cast<int>( m_currentTextures.size() )); + + m_texturesEnabled[index] = enabled; + + glActiveTexture(GL_TEXTURE0 + index); + if (enabled) + glEnable(GL_TEXTURE_2D); + else + glDisable(GL_TEXTURE_2D); +} + +bool Gfx::CGLDevice::GetTextureEnabled(int index) +{ + assert(index >= 0); + assert(index < static_cast<int>( m_currentTextures.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::SetTextureStageParams(int index, const Gfx::TextureStageParams ¶ms) +{ + assert(index >= 0); + assert(index < static_cast<int>( m_currentTextures.size() )); + + // Remember the settings + m_textureStageParams[index] = params; + + // Don't actually do anything if texture not set + if (! m_currentTextures[index].valid) + return; + + // Enable the given stage + glActiveTexture(GL_TEXTURE0 + index); + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, m_currentTextures[index].id); + + // To save some trouble + if ( (params.colorOperation == Gfx::TEX_MIX_OPER_DEFAULT) && + (params.alphaOperation == Gfx::TEX_MIX_OPER_DEFAULT) ) + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + goto after_tex_operations; + } + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + // Only these modes of getting color & alpha are used + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + + // Color operation + + if (params.colorOperation == Gfx::TEX_MIX_OPER_DEFAULT) + { + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); + goto after_tex_color; + } + else if (params.colorOperation == Gfx::TEX_MIX_OPER_REPLACE) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); + else if (params.colorOperation == Gfx::TEX_MIX_OPER_MODULATE) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + else if (params.colorOperation == Gfx::TEX_MIX_OPER_ADD) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD); + else if (params.colorOperation == Gfx::TEX_MIX_OPER_SUBTRACT) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT); + else assert(false); + + // Color arg1 + if (params.colorArg1 == Gfx::TEX_MIX_ARG_TEXTURE) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); + else if (params.colorArg1 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); + else if (params.colorArg1 == Gfx::TEX_MIX_ARG_SRC_COLOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR); + else if (params.colorArg1 == Gfx::TEX_MIX_ARG_FACTOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT); + else assert(false); + + // Color arg2 + if (params.colorArg2 == Gfx::TEX_MIX_ARG_TEXTURE) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); + else if (params.colorArg2 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS); + else if (params.colorArg2 == Gfx::TEX_MIX_ARG_SRC_COLOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR); + else if (params.colorArg2 == Gfx::TEX_MIX_ARG_FACTOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT); + else assert(false); + + +after_tex_color: + + // Alpha operation + if (params.alphaOperation == Gfx::TEX_MIX_OPER_DEFAULT) + { + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); + goto after_tex_operations; + } + else if (params.colorOperation == Gfx::TEX_MIX_OPER_REPLACE) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + else if (params.alphaOperation == Gfx::TEX_MIX_OPER_MODULATE) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + else if (params.alphaOperation == Gfx::TEX_MIX_OPER_ADD) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD); + else if (params.alphaOperation == Gfx::TEX_MIX_OPER_SUBTRACT) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_SUBTRACT); + else assert(false); + + // Alpha arg1 + if (params.alphaArg1 == Gfx::TEX_MIX_ARG_TEXTURE) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); + else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); + else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_SRC_COLOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR); + else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_FACTOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT); + else assert(false); + + // Alpha arg2 + if (params.alphaArg2 == Gfx::TEX_MIX_ARG_TEXTURE) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); + else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS); + else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_SRC_COLOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR); + else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_FACTOR) + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT); + else assert(false); + + +after_tex_operations: + + 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); + + // Disable the stage if it is set so + if ( (! m_texturing) || (! m_texturesEnabled[index]) ) + glDisable(GL_TEXTURE_2D); +} + +Gfx::TextureStageParams Gfx::CGLDevice::GetTextureStageParams(int index) +{ + assert(index >= 0); + assert(index < static_cast<int>( m_currentTextures.size() )); + + return m_textureStageParams[index]; +} + +void Gfx::CGLDevice::SetTextureFactor(const Gfx::Color &color) +{ + // Needs to be set for all texture stages + for (int index = 0; index < static_cast<int>( m_currentTextures.size() ); ++index) + { + // Activate stage + glActiveTexture(GL_TEXTURE0 + 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) + glActiveTexture(GL_TEXTURE0); + 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]); +} + +GLenum TranslateGfxPrimitive(Gfx::PrimitiveType type) +{ + GLenum flag = 0; + switch (type) + { + case Gfx::PRIMITIVE_POINTS: flag = GL_POINTS; break; + case Gfx::PRIMITIVE_LINES: flag = GL_LINES; break; + case Gfx::PRIMITIVE_LINE_STRIP: flag = GL_LINE_STRIP; break; + case Gfx::PRIMITIVE_TRIANGLES: flag = GL_TRIANGLES; break; + case Gfx::PRIMITIVE_TRIANGLE_STRIP: flag = GL_TRIANGLE_STRIP; break; + default: assert(false); break; + } + return flag; +} + +void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, const Vertex *vertices, int vertexCount) +{ + glBegin(TranslateGfxPrimitive(type)); + + glColor3f(1.0f, 1.0f, 1.0f); + + for (int i = 0; i < vertexCount; ++i) + { + glNormal3fv(const_cast<GLfloat*>(vertices[i].normal.Array())); + glMultiTexCoord2fv(GL_TEXTURE0, const_cast<GLfloat*>(vertices[i].texCoord.Array())); + glVertex3fv(const_cast<GLfloat*>(vertices[i].coord.Array())); + } + + glEnd(); +} + +void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexCol *vertices, int vertexCount) +{ + glBegin(TranslateGfxPrimitive(type)); + + for (int i = 0; i < vertexCount; ++i) + { + glColor4fv(const_cast<GLfloat*>(vertices[i].color.Array())); + glSecondaryColor3fv(const_cast<GLfloat*>(vertices[i].specular.Array())); + glMultiTexCoord2fv(GL_TEXTURE0, const_cast<GLfloat*>(vertices[i].texCoord.Array())); + glVertex3fv(const_cast<GLfloat*>(vertices[i].coord.Array())); + } + + glEnd(); +} + +void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, const VertexTex2 *vertices, int vertexCount) +{ + glBegin(TranslateGfxPrimitive(type)); + + glColor3f(1.0f, 1.0f, 1.0f); + + for (int i = 0; i < vertexCount; ++i) + { + glNormal3fv(const_cast<GLfloat*>(vertices[i].normal.Array())); + glMultiTexCoord2fv(GL_TEXTURE0, const_cast<GLfloat*>(vertices[i].texCoord.Array())); + glMultiTexCoord2fv(GL_TEXTURE1, const_cast<GLfloat*>(vertices[i].texCoord.Array())); + glVertex3fv(const_cast<GLfloat*>(vertices[i].coord.Array())); + } + + glEnd(); +} + +bool InPlane(Math::Vector normal, float originPlane, Math::Vector center, float radius) +{ + float distance = (originPlane + Math::DotProduct(normal, center)) / normal.Length(); + + if (distance < -radius) + return true; + + return false; +} + +/* + The implementation of ComputeSphereVisibility is taken from libwine's device.c + Copyright of the WINE team, licensed under GNU LGPL v 2.1 + */ + +// TODO: testing +int Gfx::CGLDevice::ComputeSphereVisibility(const Math::Vector ¢er, float radius) +{ + Math::Matrix m; + m.LoadIdentity(); + m = Math::MultiplyMatrices(m, m_worldMat); + m = Math::MultiplyMatrices(m, m_viewMat); + m = Math::MultiplyMatrices(m, m_projectionMat); + + Math::Vector vec[6]; + float originPlane[6]; + + // Left plane + vec[0].x = m.Get(4, 1) + m.Get(1, 1); + vec[0].y = m.Get(4, 2) + m.Get(1, 2); + vec[0].z = m.Get(4, 3) + m.Get(1, 3); + originPlane[0] = m.Get(4, 4) + m.Get(1, 4); + + // Right plane + vec[1].x = m.Get(4, 1) - m.Get(1, 1); + vec[1].y = m.Get(4, 2) - m.Get(1, 2); + vec[1].z = m.Get(4, 3) - m.Get(1, 3); + originPlane[1] = m.Get(4, 4) - m.Get(1, 4); + + // Top plane + vec[2].x = m.Get(4, 1) - m.Get(2, 1); + vec[2].y = m.Get(4, 2) - m.Get(2, 2); + vec[2].z = m.Get(4, 3) - m.Get(2, 3); + originPlane[2] = m.Get(4, 4) - m.Get(2, 4); + + // Bottom plane + vec[3].x = m.Get(4, 1) + m.Get(2, 1); + vec[3].y = m.Get(4, 2) + m.Get(2, 2); + vec[3].z = m.Get(4, 3) + m.Get(2, 3); + originPlane[3] = m.Get(4, 4) + m.Get(2, 4); + + // Front plane + vec[4].x = m.Get(3, 1); + vec[4].y = m.Get(3, 2); + vec[4].z = m.Get(3, 3); + originPlane[4] = m.Get(3, 4); + + // Back plane + vec[5].x = m.Get(4, 1) - m.Get(3, 1); + vec[5].y = m.Get(4, 2) - m.Get(3, 2); + vec[5].z = m.Get(4, 3) - m.Get(3, 3); + originPlane[5] = m.Get(4, 4) - m.Get(3, 4); + + int result = 0; + + if (InPlane(vec[0], originPlane[0], center, radius)) + result |= Gfx::INTERSECT_PLANE_LEFT; + if (InPlane(vec[1], originPlane[1], center, radius)) + result |= Gfx::INTERSECT_PLANE_RIGHT; + if (InPlane(vec[2], originPlane[2], center, radius)) + result |= Gfx::INTERSECT_PLANE_TOP; + if (InPlane(vec[3], originPlane[3], center, radius)) + result |= Gfx::INTERSECT_PLANE_BOTTOM; + if (InPlane(vec[4], originPlane[4], center, radius)) + result |= Gfx::INTERSECT_PLANE_FRONT; + if (InPlane(vec[5], originPlane[5], center, radius)) + result |= Gfx::INTERSECT_PLANE_BACK; + + return result; +} + +void Gfx::CGLDevice::SetRenderState(Gfx::RenderState state, bool enabled) +{ + if (state == Gfx::RENDER_STATE_DEPTH_WRITE) + { + glDepthMask(enabled ? GL_TRUE : GL_FALSE); + return; + } + else if (state == Gfx::RENDER_STATE_LIGHTING) + { + m_lighting = enabled; + + if (enabled) + glEnable(GL_LIGHTING); + else + glDisable(GL_LIGHTING); + + if (enabled) + { + for (int index = 0; index < static_cast<int>( m_lights.size() ); ++index) + UpdateLightPosition(index); + } + + return; + } + else if (state == Gfx::RENDER_STATE_TEXTURING) + { + m_texturing = enabled; + + // Enable/disable stages with new setting + for (int index = 0; index < static_cast<int>( m_currentTextures.size() ); ++index) + { + glActiveTexture(GL_TEXTURE0 + index); + if (m_texturing && m_texturesEnabled[index]) + glEnable(GL_TEXTURE_2D); + else + glDisable(GL_TEXTURE_2D); + } + + return; + } + + GLenum flag = 0; + + switch (state) + { + case Gfx::RENDER_STATE_BLENDING: flag = GL_BLEND; break; + case Gfx::RENDER_STATE_FOG: flag = GL_FOG; break; + case Gfx::RENDER_STATE_DEPTH_TEST: flag = GL_DEPTH_TEST; break; + case Gfx::RENDER_STATE_ALPHA_TEST: flag = GL_ALPHA_TEST; break; + case Gfx::RENDER_STATE_CULLING: flag = GL_CULL_FACE; break; + case Gfx::RENDER_STATE_DITHERING: flag = GL_DITHER; break; + default: assert(false); break; + } + + if (enabled) + glEnable(flag); + else + glDisable(flag); +} + +bool Gfx::CGLDevice::GetRenderState(Gfx::RenderState state) +{ + if (state == Gfx::RENDER_STATE_LIGHTING) + return m_lighting; + + if (state == Gfx::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_BLENDING: flag = GL_BLEND; break; + case Gfx::RENDER_STATE_FOG: flag = GL_FOG; break; + case Gfx::RENDER_STATE_DEPTH_TEST: flag = GL_DEPTH_TEST; break; + case Gfx::RENDER_STATE_ALPHA_TEST: flag = GL_ALPHA_TEST; break; + case Gfx::RENDER_STATE_CULLING: flag = GL_CULL_FACE; break; + case Gfx::RENDER_STATE_DITHERING: flag = GL_DITHER; break; + default: assert(false); break; + } + + GLboolean result = GL_FALSE; + glGetBooleanv(flag, &result); + + return result == GL_TRUE; +} + +Gfx::CompFunc TranslateGLCompFunc(GLenum flag) +{ + switch (flag) + { + case GL_NEVER: return Gfx::COMP_FUNC_NEVER; + case GL_LESS: return Gfx::COMP_FUNC_LESS; + case GL_EQUAL: return Gfx::COMP_FUNC_EQUAL; + case GL_NOTEQUAL: return Gfx::COMP_FUNC_NOTEQUAL; + case GL_LEQUAL: return Gfx::COMP_FUNC_LEQUAL; + case GL_GREATER: return Gfx::COMP_FUNC_GREATER; + case GL_GEQUAL: return Gfx::COMP_FUNC_GEQUAL; + case GL_ALWAYS: return Gfx::COMP_FUNC_ALWAYS; + default: assert(false); break; + } + return Gfx::COMP_FUNC_NEVER; +} + +GLenum TranslateGfxCompFunc(Gfx::CompFunc func) +{ + switch (func) + { + case Gfx::COMP_FUNC_NEVER: return GL_NEVER; + case Gfx::COMP_FUNC_LESS: return GL_LESS; + case Gfx::COMP_FUNC_EQUAL: return GL_EQUAL; + case Gfx::COMP_FUNC_NOTEQUAL: return GL_NOTEQUAL; + case Gfx::COMP_FUNC_LEQUAL: return GL_LEQUAL; + case Gfx::COMP_FUNC_GREATER: return GL_GREATER; + case Gfx::COMP_FUNC_GEQUAL: return GL_GEQUAL; + case Gfx::COMP_FUNC_ALWAYS: return GL_ALWAYS; + default: assert(false); break; + } + return 0; +} + +void Gfx::CGLDevice::SetDepthTestFunc(Gfx::CompFunc func) +{ + glDepthFunc(TranslateGfxCompFunc(func)); +} + +Gfx::CompFunc Gfx::CGLDevice::GetDepthTestFunc() +{ + GLint flag = 0; + glGetIntegerv(GL_DEPTH_FUNC, &flag); + return TranslateGLCompFunc(static_cast<GLenum>(flag)); +} + +void Gfx::CGLDevice::SetDepthBias(float factor) +{ + glPolygonOffset(factor, 0.0f); +} + +float Gfx::CGLDevice::GetDepthBias() +{ + GLfloat result = 0.0f; + glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &result); + return result; +} + +void Gfx::CGLDevice::SetAlphaTestFunc(Gfx::CompFunc func, float refValue) +{ + glAlphaFunc(TranslateGfxCompFunc(func), refValue); +} + +void Gfx::CGLDevice::GetAlphaTestFunc(Gfx::CompFunc &func, float &refValue) +{ + GLint flag = 0; + glGetIntegerv(GL_ALPHA_TEST_FUNC, &flag); + func = TranslateGLCompFunc(static_cast<GLenum>(flag)); + + glGetFloatv(GL_ALPHA_TEST_REF, static_cast<GLfloat*>(&refValue)); +} + +Gfx::BlendFunc TranslateGLBlendFunc(GLenum flag) +{ + switch (flag) + { + case GL_ZERO: return Gfx::BLEND_ZERO; + case GL_ONE: return Gfx::BLEND_ONE; + case GL_SRC_COLOR: return Gfx::BLEND_SRC_COLOR; + case GL_ONE_MINUS_SRC_COLOR: return Gfx::BLEND_INV_SRC_COLOR; + case GL_DST_COLOR: return Gfx::BLEND_DST_COLOR; + case GL_ONE_MINUS_DST_COLOR: return Gfx::BLEND_INV_DST_COLOR; + case GL_SRC_ALPHA: return Gfx::BLEND_SRC_ALPHA; + case GL_ONE_MINUS_SRC_ALPHA: return Gfx::BLEND_INV_SRC_ALPHA; + case GL_DST_ALPHA: return Gfx::BLEND_DST_ALPHA; + case GL_ONE_MINUS_DST_ALPHA: return Gfx::BLEND_INV_DST_ALPHA; + case GL_SRC_ALPHA_SATURATE: return Gfx::BLEND_SRC_ALPHA_SATURATE; + default: assert(false); break; + } + + return Gfx::BLEND_ZERO; +} + +GLenum TranslateGfxBlendFunc(Gfx::BlendFunc func) +{ + switch (func) + { + case Gfx::BLEND_ZERO: return GL_ZERO; + case Gfx::BLEND_ONE: return GL_ONE; + case Gfx::BLEND_SRC_COLOR: return GL_SRC_COLOR; + case Gfx::BLEND_INV_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR; + case Gfx::BLEND_DST_COLOR: return GL_DST_COLOR; + case Gfx::BLEND_INV_DST_COLOR: return GL_ONE_MINUS_DST_COLOR; + case Gfx::BLEND_SRC_ALPHA: return GL_SRC_ALPHA; + case Gfx::BLEND_INV_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA; + case Gfx::BLEND_DST_ALPHA: return GL_DST_ALPHA; + case Gfx::BLEND_INV_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; + case Gfx::BLEND_SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE; + default: assert(false); break; + } + return 0; +} + +void Gfx::CGLDevice::SetBlendFunc(Gfx::BlendFunc srcBlend, Gfx::BlendFunc dstBlend) +{ + glBlendFunc(TranslateGfxBlendFunc(srcBlend), TranslateGfxBlendFunc(dstBlend)); +} + +void Gfx::CGLDevice::GetBlendFunc(Gfx::BlendFunc &srcBlend, Gfx::BlendFunc &dstBlend) +{ + GLint srcFlag = 0; + glGetIntegerv(GL_ALPHA_TEST_FUNC, &srcFlag); + srcBlend = TranslateGLBlendFunc(static_cast<GLenum>(srcFlag)); + + GLint dstFlag = 0; + glGetIntegerv(GL_ALPHA_TEST_FUNC, &dstFlag); + dstBlend = TranslateGLBlendFunc(static_cast<GLenum>(dstFlag)); +} + +void Gfx::CGLDevice::SetClearColor(const Gfx::Color &color) +{ + glClearColor(color.r, color.g, color.b, color.a); +} + +Gfx::Color Gfx::CGLDevice::GetClearColor() +{ + GLfloat color[4] = { 0.0f }; + glGetFloatv(GL_COLOR_CLEAR_VALUE, color); + return Gfx::Color(color[0], color[1], color[2], color[3]); +} + +void Gfx::CGLDevice::SetGlobalAmbient(const Gfx::Color &color) +{ + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.Array()); +} + +Gfx::Color Gfx::CGLDevice::GetGlobalAmbient() +{ + GLfloat color[4] = { 0.0f }; + glGetFloatv(GL_LIGHT_MODEL_AMBIENT, color); + return Gfx::Color(color[0], color[1], color[2], color[3]); +} + +void Gfx::CGLDevice::SetFogParams(Gfx::FogMode mode, const Gfx::Color &color, float start, float end, float density) +{ + if (mode == Gfx::FOG_LINEAR) glFogi(GL_FOG_MODE, GL_LINEAR); + else if (mode == Gfx::FOG_EXP) glFogi(GL_FOG_MODE, GL_EXP); + else if (mode == Gfx::FOG_EXP2) glFogi(GL_FOG_MODE, GL_EXP2); + else assert(false); + + glFogf(GL_FOG_START, start); + glFogf(GL_FOG_END, end); + glFogf(GL_FOG_DENSITY, density); +} + +void Gfx::CGLDevice::GetFogParams(Gfx::FogMode &mode, Gfx::Color &color, float &start, float &end, float &density) +{ + GLint flag = 0; + glGetIntegerv(GL_FOG_MODE, &flag); + if (flag == GL_LINEAR) mode = Gfx::FOG_LINEAR; + else if (flag == GL_EXP) mode = Gfx::FOG_EXP; + else if (flag == GL_EXP2) mode = Gfx::FOG_EXP2; + else assert(false); + + glGetFloatv(GL_FOG_START, static_cast<GLfloat*>(&start)); + glGetFloatv(GL_FOG_END, static_cast<GLfloat*>(&end)); + glGetFloatv(GL_FOG_DENSITY, static_cast<GLfloat*>(&density)); +} + +void Gfx::CGLDevice::SetCullMode(Gfx::CullMode mode) +{ + if (mode == Gfx::CULL_CW) glCullFace(GL_CW); + else if (mode == Gfx::CULL_CCW) glCullFace(GL_CCW); + else assert(false); +} + +Gfx::CullMode Gfx::CGLDevice::GetCullMode() +{ + GLint flag = 0; + glGetIntegerv(GL_CULL_FACE, &flag); + if (flag == GL_CW) return Gfx::CULL_CW; + else if (flag == GL_CCW) return Gfx::CULL_CCW; + else assert(false); + 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() +{ + GLint flag = 0; + glGetIntegerv(GL_SHADE_MODEL, &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); + else if (mode == Gfx::FILL_LINES) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + else if (mode == Gfx::FILL_FILL) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + else assert(false); +} + +Gfx::FillMode Gfx::CGLDevice::GetFillMode() +{ + GLint flag = 0; + glGetIntegerv(GL_POLYGON_MODE, &flag); + 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); + return Gfx::FILL_POINT; +} diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h index a2fb4a0..1864000 100644 --- a/src/graphics/opengl/gldevice.h +++ b/src/graphics/opengl/gldevice.h @@ -19,13 +19,185 @@ #pragma once -#include "graphics/common/device.h" +#include "graphics/core/device.h" + +#include <string> +#include <vector> +#include <set> + namespace Gfx { +/** + \struct GLDeviceConfig + \brief Additional config with OpenGL-specific settings */ +struct GLDeviceConfig : public DeviceConfig +{ + //! Size of red channel in bits + int redSize; + //! Size of green channel in bits + int greenSize; + //! Size of blue channel in bits + int blueSize; + //! Size of alpha channel in bits + int alphaSize; + //! Color depth in bits + int depthSize; + + //! Force hardware acceleration (video mode set will fail on lack of hw accel) + bool hardwareAccel; + + //! Constructor calls LoadDefaults() + GLDeviceConfig() { LoadDefault(); } + + //! Loads the default values + void LoadDefault(); +}; + +struct GLDevicePrivate; + +/** + \class CGLDevice + \brief Implementation of CDevice interface in OpenGL + + Provides the concrete implementation of 3D device in OpenGL. + + This class should be initialized (by calling Initialize() ) only after + setting the video mode by CApplication, once the OpenGL context is defined. + Because of that, CGLDeviceConfig is outside the CDevice class and must be set + in CApplication. +*/ class CGLDevice : public Gfx::CDevice { - // TODO +public: + CGLDevice(const Gfx::GLDeviceConfig &config); + virtual ~CGLDevice(); + + virtual bool GetWasInit(); + virtual std::string GetError(); + + virtual bool Create(); + virtual void Destroy(); + + void ConfigChanged(const Gfx::GLDeviceConfig &newConfig); + + virtual void BeginScene(); + virtual void EndScene(); + + virtual void Clear(); + + virtual void SetTransform(Gfx::TransformType type, const Math::Matrix &matrix); + virtual const Math::Matrix& GetTransform(Gfx::TransformType type); + virtual void MultiplyTransform(Gfx::TransformType type, const Math::Matrix &matrix); + + virtual void SetMaterial(const Gfx::Material &material); + virtual const Gfx::Material& GetMaterial(); + + virtual int GetMaxLightCount(); + virtual void SetLight(int index, const Gfx::Light &light); + virtual const Gfx::Light& GetLight(int index); + virtual void SetLightEnabled(int index, bool enabled); + virtual bool GetLightEnabled(int index); + + virtual Gfx::Texture CreateTexture(CImage *image, const Gfx::TextureCreateParams ¶ms); + virtual void DestroyTexture(const Gfx::Texture &texture); + virtual void DestroyAllTextures(); + + virtual int GetMaxTextureCount(); + virtual void SetTexture(int index, const Gfx::Texture &texture); + virtual Gfx::Texture GetTexture(int index); + virtual void SetTextureEnabled(int index, bool enabled); + virtual bool GetTextureEnabled(int index); + + virtual void SetTextureStageParams(int index, const Gfx::TextureStageParams ¶ms); + virtual Gfx::TextureStageParams GetTextureStageParams(int index); + + virtual void SetTextureFactor(const Gfx::Color &color); + virtual Gfx::Color GetTextureFactor(); + + virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::Vertex *vertices, int vertexCount); + virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexCol *vertices, int vertexCount); + virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexTex2 *vertices, int vertexCount); + + virtual int ComputeSphereVisibility(const Math::Vector ¢er, float radius); + + virtual void SetRenderState(Gfx::RenderState state, bool enabled); + virtual bool GetRenderState(Gfx::RenderState state); + + virtual void SetDepthTestFunc(Gfx::CompFunc func); + virtual Gfx::CompFunc GetDepthTestFunc(); + + virtual void SetDepthBias(float factor); + virtual float GetDepthBias(); + + virtual void SetAlphaTestFunc(Gfx::CompFunc func, float refValue); + virtual void GetAlphaTestFunc(Gfx::CompFunc &func, float &refValue); + + virtual void SetBlendFunc(Gfx::BlendFunc srcBlend, Gfx::BlendFunc dstBlend); + virtual void GetBlendFunc(Gfx::BlendFunc &srcBlend, Gfx::BlendFunc &dstBlend); + + virtual void SetClearColor(const Gfx::Color &color); + virtual Gfx::Color GetClearColor(); + + virtual void SetGlobalAmbient(const Gfx::Color &color); + virtual Gfx::Color GetGlobalAmbient(); + + virtual void SetFogParams(Gfx::FogMode mode, const Gfx::Color &color, float start, float end, float density); + virtual void GetFogParams(Gfx::FogMode &mode, Gfx::Color &color, float &start, float &end, float &density); + + 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(); + +private: + //! Updates internal modelview matrix + void UpdateModelviewMatrix(); + //! Updates position for given light based on transformation matrices + void UpdateLightPosition(int index); + +private: + //! Current config + Gfx::GLDeviceConfig m_config; + //! Was initialized? + bool m_wasInit; + //! Last encountered error + std::string m_error; + + //! Current world matrix + Math::Matrix m_worldMat; + //! Current view matrix + Math::Matrix m_viewMat; + //! OpenGL modelview matrix = world matrix * view matrix + Math::Matrix m_modelviewMat; + //! Current projection matrix + Math::Matrix m_projectionMat; + + //! The current material + Gfx::Material m_material; + + //! Whether lighting is enabled + bool m_lighting; + //! Current lights + std::vector<Gfx::Light> m_lights; + //! Current lights enable status + std::vector<bool> m_lightsEnabled; + + //! Whether texturing is enabled in general + bool m_texturing; + //! Current textures; \c NULL value means unassigned + std::vector<Gfx::Texture> m_currentTextures; + //! Current texture stages enable status + std::vector<bool> m_texturesEnabled; + //! Current texture params + std::vector<Gfx::TextureStageParams> m_textureStageParams; + + //! Set of all created textures + std::set<Gfx::Texture> m_allTextures; }; }; // namespace Gfx diff --git a/src/graphics/opengl/glengine.cpp b/src/graphics/opengl/glengine.cpp deleted file mode 100644 index 9aab348..0000000 --- a/src/graphics/opengl/glengine.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// * 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/. - -// glengine.h - -#include "graphics/opengl/glengine.h" - -// TODO
\ No newline at end of file diff --git a/src/graphics/opengl/glengine.h b/src/graphics/opengl/glengine.h deleted file mode 100644 index fa67bfe..0000000 --- a/src/graphics/opengl/glengine.h +++ /dev/null @@ -1,32 +0,0 @@ -// * 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/. - -// glengine.h - -#pragma once - - -#include "graphics/common/engine.h" - -namespace Gfx -{ - -class CGLEngine : public Gfx::CEngine -{ - // TODO -}; - -}; diff --git a/src/graphics/opengl/test/CMakeLists.txt b/src/graphics/opengl/test/CMakeLists.txt new file mode 100644 index 0000000..8ed7364 --- /dev/null +++ b/src/graphics/opengl/test/CMakeLists.txt @@ -0,0 +1,87 @@ +cmake_minimum_required(VERSION 2.8) + +find_package(OpenGL REQUIRED) +find_package(SDL REQUIRED) +find_package(SDL_image REQUIRED) +find_package(PNG REQUIRED) + +set(CMAKE_BUILD_TYPE debug) +set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0") + +set(ADD_LIBS "") + +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(PLATFORM_WINDOWS 1) + set(PLATFORM_LINUX 0) + set(PLATFORM_OTHER 0) +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(PLATFORM_WINDOWS 0) + set(PLATFORM_LINUX 1) + set(PLATFORM_OTHER 0) + set(ADD_LIBS "-lrt") +else() + set(PLATFORM_WINDOWS 0) + set(PLATFORM_LINUX 0) + set(PLATFORM_OTHER 1) +endif() + +configure_file(../../../common/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/common/config.h) + + +set(TEXTURE_SOURCES +../gldevice.cpp +../../../common/logger.cpp +../../../common/image.cpp +texture_test.cpp +) + +set(MODEL_SOURCES +../gldevice.cpp +../../engine/modelfile.cpp +../../../common/logger.cpp +../../../common/image.cpp +../../../common/iman.cpp +../../../common/stringutils.cpp +../../../app/system.cpp +model_test.cpp +) + +set(TRANSFORM_SOURCES +../gldevice.cpp +../../../common/logger.cpp +../../../common/image.cpp +../../../common/iman.cpp +../../../app/system.cpp +transform_test.cpp +) + +set(LIGHT_SOURCES +../gldevice.cpp +../../../common/logger.cpp +../../../common/image.cpp +../../../common/iman.cpp +../../../app/system.cpp +light_test.cpp +) + +include_directories(../../../ ${CMAKE_CURRENT_BINARY_DIR}) + +set(LIBS +${SDL_LIBRARY} +${SDLIMAGE_LIBRARY} +${OPENGL_LIBRARY} +${PNG_LIBRARIES} +${ADD_LIBS} +) + +add_executable(texture_test ${TEXTURE_SOURCES}) +target_link_libraries(texture_test ${LIBS}) + +add_executable(model_test ${MODEL_SOURCES}) +target_link_libraries(model_test ${LIBS}) + +add_executable(transform_test ${TRANSFORM_SOURCES}) +target_link_libraries(transform_test ${LIBS}) + +add_executable(light_test ${LIGHT_SOURCES}) +target_link_libraries(light_test ${LIBS}) diff --git a/src/graphics/opengl/test/README.txt b/src/graphics/opengl/test/README.txt new file mode 100644 index 0000000..c618415 --- /dev/null +++ b/src/graphics/opengl/test/README.txt @@ -0,0 +1,9 @@ +Test programs for OpenGL engine: + - texture_test -> multitexturing test with 2 textures (included as files: ./tex1.png, ./tex2.png) + - model_test -> simple model viewer to test model loading + usage: ./model_test {dxf|mod} model_file + second argument is the loaded format (DXF or Colobot .mod files) + requires ./tex folder (or symlink) with Colobot textures + viewer is controlled from keyboard - the bindings can be found in code + - transform_test -> simple "walk around" test for world & view transformations + - light test -> test for lighting diff --git a/src/graphics/opengl/test/light_test.cpp b/src/graphics/opengl/test/light_test.cpp new file mode 100644 index 0000000..80fa911 --- /dev/null +++ b/src/graphics/opengl/test/light_test.cpp @@ -0,0 +1,437 @@ +#include "app/system.h" +#include "common/logger.h" +#include "common/image.h" +#include "common/iman.h" +#include "graphics/opengl/gldevice.h" +#include "math/geometry.h" + +#include <SDL/SDL.h> +#include <SDL/SDL_image.h> +#include <unistd.h> + +#include <iostream> +#include <map> + +enum KeySlots +{ + K_Forward, + K_Back, + K_Left, + K_Right, + K_Up, + K_Down, + K_Count +}; +bool KEYMAP[K_Count] = { false }; + +Math::Point MOUSE_POS_BASE; + +Math::Vector TRANSLATION(0.0f, 2.0f, 0.0f); +Math::Vector ROTATION, ROTATION_BASE; + +float CUBE_ORBIT = 0.0f; + +const int FRAME_DELAY = 5000; + +SystemTimeStamp *PREV_TIME = NULL, *CURR_TIME = NULL; + +void Init(Gfx::CGLDevice *device) +{ + device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true); + device->SetShadeModel(Gfx::SHADE_SMOOTH); +} + +void Render(Gfx::CGLDevice *device) +{ + device->BeginScene(); + + /* Unlit part of scene */ + + device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, false); + device->SetRenderState(Gfx::RENDER_STATE_CULLING, false); // Double-sided drawing + + Math::Matrix persp; + Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 100.0f); + device->SetTransform(Gfx::TRANSFORM_PROJECTION, persp); + + + Math::Matrix viewMat; + Math::Matrix mat; + + viewMat.LoadIdentity(); + + Math::LoadRotationXMatrix(mat, -ROTATION.x); + viewMat = Math::MultiplyMatrices(viewMat, mat); + + Math::LoadRotationYMatrix(mat, -ROTATION.y); + viewMat = Math::MultiplyMatrices(viewMat, mat); + + Math::LoadTranslationMatrix(mat, -TRANSLATION); + viewMat = Math::MultiplyMatrices(viewMat, mat); + + device->SetTransform(Gfx::TRANSFORM_VIEW, viewMat); + + Math::Matrix worldMat; + worldMat.LoadIdentity(); + device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat); + + Gfx::VertexCol line[2] = { Gfx::VertexCol() }; + + for (int x = -40; x <= 40; ++x) + { + line[0].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f); + line[0].coord.z = -40; + line[0].coord.x = x; + line[1].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f); + line[1].coord.z = 40; + line[1].coord.x = x; + device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2); + } + + for (int z = -40; z <= 40; ++z) + { + line[0].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f); + line[0].coord.z = z; + line[0].coord.x = -40; + line[1].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f); + line[1].coord.z = z; + line[1].coord.x = 40; + device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2); + } + + + Gfx::VertexCol quad[6] = { Gfx::VertexCol() }; + + quad[0].coord = Math::Vector(-1.0f, -1.0f, 0.0f); + quad[1].coord = Math::Vector( 1.0f, -1.0f, 0.0f); + quad[2].coord = Math::Vector(-1.0f, 1.0f, 0.0f); + quad[3].coord = Math::Vector( 1.0f, 1.0f, 0.0f); + + for (int i = 0; i < 6; ++i) + quad[i].color = Gfx::Color(1.0f, 1.0f, 0.0f); + + Math::LoadTranslationMatrix(worldMat, Math::Vector(40.0f, 2.0f, 40.0f)); + device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat); + + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4); + + for (int i = 0; i < 6; ++i) + quad[i].color = Gfx::Color(0.0f, 1.0f, 1.0f); + + Math::LoadTranslationMatrix(worldMat, Math::Vector(-40.0f, 2.0f, -40.0f)); + device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat); + + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4); + + for (int i = 0; i < 6; ++i) + quad[i].color = Gfx::Color(1.0f, 0.0f, 1.0f); + + Math::LoadTranslationMatrix(worldMat, Math::Vector(10.0f, 4.5f, 5.0f)); + device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat); + + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4); + + /* Moving lit cube */ + device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, true); + device->SetRenderState(Gfx::RENDER_STATE_CULLING, true); // Culling (CCW faces) + + device->SetGlobalAmbient(Gfx::Color(0.4f, 0.4f, 0.4f)); + + Gfx::Light light1; + light1.type = Gfx::LIGHT_POINT; + light1.position = Math::Vector(10.0f, 4.5f, 5.0f); + light1.ambient = Gfx::Color(0.2f, 0.2f, 0.2f); + light1.diffuse = Gfx::Color(1.0f, 0.1f, 0.1f); + light1.specular = Gfx::Color(0.0f, 0.0f, 0.0f); + device->SetLight(0, light1); + device->SetLightEnabled(0, true); + + /*Gfx::Light light2; + device->SetLight(1, light2); + device->SetLightEnabled(1, true);*/ + + Gfx::Material material; + material.ambient = Gfx::Color(0.3f, 0.3f, 0.3f); + material.diffuse = Gfx::Color(0.8f, 0.7f, 0.6f); + material.specular = Gfx::Color(0.0f, 0.0f, 0.0f); + device->SetMaterial(material); + + const Gfx::Vertex cube[6][4] = + { + { + // Front + Gfx::Vertex(Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f)), + Gfx::Vertex(Math::Vector( 1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f)), + Gfx::Vertex(Math::Vector(-1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f)), + Gfx::Vertex(Math::Vector( 1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f)) + }, + + { + // Back + Gfx::Vertex(Math::Vector( 1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f)), + Gfx::Vertex(Math::Vector(-1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f)), + Gfx::Vertex(Math::Vector( 1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f)), + Gfx::Vertex(Math::Vector(-1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f)) + }, + + { + // Top + Gfx::Vertex(Math::Vector(-1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 1.0f, 0.0f)), + Gfx::Vertex(Math::Vector( 1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 1.0f, 0.0f)), + Gfx::Vertex(Math::Vector(-1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 1.0f, 0.0f)), + Gfx::Vertex(Math::Vector( 1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 1.0f, 0.0f)) + }, + + { + // Bottom + Gfx::Vertex(Math::Vector(-1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, -1.0f, 0.0f)), + Gfx::Vertex(Math::Vector( 1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, -1.0f, 0.0f)), + Gfx::Vertex(Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, -1.0f, 0.0f)), + Gfx::Vertex(Math::Vector( 1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, -1.0f, 0.0f)) + }, + + { + // Left + Gfx::Vertex(Math::Vector(-1.0f, -1.0f, 1.0f), Math::Vector(-1.0f, 0.0f, 0.0f)), + Gfx::Vertex(Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector(-1.0f, 0.0f, 0.0f)), + Gfx::Vertex(Math::Vector(-1.0f, 1.0f, 1.0f), Math::Vector(-1.0f, 0.0f, 0.0f)), + Gfx::Vertex(Math::Vector(-1.0f, 1.0f, -1.0f), Math::Vector(-1.0f, 0.0f, 0.0f)) + }, + + { + // Right + Gfx::Vertex(Math::Vector( 1.0f, -1.0f, -1.0f), Math::Vector( 1.0f, 0.0f, 0.0f)), + Gfx::Vertex(Math::Vector( 1.0f, -1.0f, 1.0f), Math::Vector( 1.0f, 0.0f, 0.0f)), + Gfx::Vertex(Math::Vector( 1.0f, 1.0f, -1.0f), Math::Vector( 1.0f, 0.0f, 0.0f)), + Gfx::Vertex(Math::Vector( 1.0f, 1.0f, 1.0f), Math::Vector( 1.0f, 0.0f, 0.0f)) + } + }; + + Math::Matrix cubeTrans; + Math::LoadTranslationMatrix(cubeTrans, Math::Vector(10.0f, 2.0f, 5.0f)); + Math::Matrix cubeRot; + Math::LoadRotationMatrix(cubeRot, Math::Vector(0.0f, 1.0f, 0.0f), CUBE_ORBIT); + Math::Matrix cubeRotInv; + Math::LoadRotationMatrix(cubeRotInv, Math::Vector(0.0f, 1.0f, 0.0f), -CUBE_ORBIT); + Math::Matrix cubeTransRad; + Math::LoadTranslationMatrix(cubeTransRad, Math::Vector(0.0f, 0.0f, 6.0f)); + worldMat = Math::MultiplyMatrices(cubeTransRad, cubeRotInv); + worldMat = Math::MultiplyMatrices(cubeRot, worldMat); + worldMat = Math::MultiplyMatrices(cubeTrans, worldMat); + device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat); + + for (int i = 0; i < 6; ++i) + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, cube[i], 4); + + device->EndScene(); +} + +void Update() +{ + const float TRANS_SPEED = 6.0f; // units / sec + + GetCurrentTimeStamp(CURR_TIME); + float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC); + CopyTimeStamp(PREV_TIME, CURR_TIME); + + CUBE_ORBIT += timeDiff * (Math::PI / 4.0f); + + Math::Vector incTrans; + + if (KEYMAP[K_Forward]) + incTrans.z = +TRANS_SPEED * timeDiff; + if (KEYMAP[K_Back]) + incTrans.z = -TRANS_SPEED * timeDiff; + if (KEYMAP[K_Right]) + incTrans.x = +TRANS_SPEED * timeDiff; + if (KEYMAP[K_Left]) + incTrans.x = -TRANS_SPEED * timeDiff; + if (KEYMAP[K_Up]) + incTrans.y = +TRANS_SPEED * timeDiff; + if (KEYMAP[K_Down]) + incTrans.y = -TRANS_SPEED * timeDiff; + + Math::Point rotTrans = Math::RotatePoint(-ROTATION.y, Math::Point(incTrans.x, incTrans.z)); + incTrans.x = rotTrans.x; + incTrans.z = rotTrans.y; + TRANSLATION += incTrans; +} + +void KeyboardDown(SDLKey key) +{ + switch (key) + { + case SDLK_w: + KEYMAP[K_Forward] = true; + break; + case SDLK_s: + KEYMAP[K_Back] = true; + break; + case SDLK_d: + KEYMAP[K_Right] = true; + break; + case SDLK_a: + KEYMAP[K_Left] = true; + break; + case SDLK_z: + KEYMAP[K_Down] = true; + break; + case SDLK_x: + KEYMAP[K_Up] = true; + break; + default: + break; + } +} + +void KeyboardUp(SDLKey key) +{ + switch (key) + { + case SDLK_w: + KEYMAP[K_Forward] = false; + break; + case SDLK_s: + KEYMAP[K_Back] = false; + break; + case SDLK_d: + KEYMAP[K_Right] = false; + break; + case SDLK_a: + KEYMAP[K_Left] = false; + break; + case SDLK_z: + KEYMAP[K_Down] = false; + break; + case SDLK_x: + KEYMAP[K_Up] = false; + break; + default: + break; + } +} + +void MouseMove(int x, int y) +{ + Math::Point currentPos((float)x, (float)y); + + static bool first = true; + if (first || (x < 10) || (y < 10) || (x > 790) || (y > 590)) + { + SDL_WarpMouse(400, 300); + MOUSE_POS_BASE.x = 400; + MOUSE_POS_BASE.y = 300; + ROTATION_BASE = ROTATION; + first = false; + return; + } + + ROTATION.y = ROTATION_BASE.y + ((float) (x - MOUSE_POS_BASE.x) / 800.0f) * Math::PI; + ROTATION.x = ROTATION_BASE.x + ((float) (y - MOUSE_POS_BASE.y) / 600.0f) * Math::PI; +} + +int main(int argc, char *argv[]) +{ + CLogger logger; + + PREV_TIME = CreateTimeStamp(); + CURR_TIME = CreateTimeStamp(); + + GetCurrentTimeStamp(PREV_TIME); + GetCurrentTimeStamp(CURR_TIME); + + CInstanceManager iMan; + + // Without any error checking, for simplicity + + SDL_Init(SDL_INIT_VIDEO); + + IMG_Init(IMG_INIT_PNG); + + const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); + + Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE; + + if (videoInfo->hw_available) + videoFlags |= SDL_HWSURFACE; + else + videoFlags |= SDL_SWSURFACE; + + if (videoInfo->blit_hw) + videoFlags |= SDL_HWACCEL; + + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8); + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags); + + + SDL_WM_SetCaption("Light Test", "Light Test"); + + //SDL_WM_GrabInput(SDL_GRAB_ON); + SDL_ShowCursor(SDL_DISABLE); + + Gfx::CGLDevice *device = new Gfx::CGLDevice(); + device->Create(); + + Init(device); + + bool done = false; + while (! done) + { + Render(device); + Update(); + + SDL_GL_SwapBuffers(); + + SDL_Event event; + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT) + { + break; + done = true; + } + else if (event.type == SDL_KEYDOWN) + { + if (event.key.keysym.sym == SDLK_q) + { + done = true; + break; + } + else + KeyboardDown(event.key.keysym.sym); + } + else if (event.type == SDL_KEYUP) + KeyboardUp(event.key.keysym.sym); + else if (event.type == SDL_MOUSEMOTION) + MouseMove(event.motion.x, event.motion.y); + } + + usleep(FRAME_DELAY); + } + + //SDL_WM_GrabInput(SDL_GRAB_OFF); + SDL_ShowCursor(SDL_ENABLE); + + device->Destroy(); + delete device; + + SDL_FreeSurface(surface); + + IMG_Quit(); + + SDL_Quit(); + + DestroyTimeStamp(PREV_TIME); + DestroyTimeStamp(CURR_TIME); + + return 0; +} diff --git a/src/graphics/opengl/test/model_test.cpp b/src/graphics/opengl/test/model_test.cpp new file mode 100644 index 0000000..3e8efe6 --- /dev/null +++ b/src/graphics/opengl/test/model_test.cpp @@ -0,0 +1,377 @@ +#include "app/system.h" +#include "common/logger.h" +#include "common/image.h" +#include "common/iman.h" +#include "graphics/engine/modelfile.h" +#include "graphics/opengl/gldevice.h" +#include "math/geometry.h" + +#include <SDL/SDL.h> +#include <SDL/SDL_image.h> +#include <unistd.h> + +#include <iostream> +#include <map> + +enum KeySlots +{ + K_RotXUp, + K_RotXDown, + K_RotYLeft, + K_RotYRight, + K_Forward, + K_Back, + K_Left, + K_Right, + K_Up, + K_Down, + K_Count +}; +bool KEYMAP[K_Count] = { false }; + +Math::Vector TRANSLATION(0.0f, 0.0f, 30.0f); +Math::Vector ROTATION; + +const int FRAME_DELAY = 5000; + +std::map<std::string, Gfx::Texture> TEXS; + +SystemTimeStamp *PREV_TIME = NULL, *CURR_TIME = NULL; + +Gfx::Texture GetTexture(const std::string &name) +{ + std::map<std::string, Gfx::Texture>::iterator it = TEXS.find(name); + if (it == TEXS.end()) + return Gfx::Texture(); + + return (*it).second; +} + +void LoadTexture(Gfx::CGLDevice *device, const std::string &name) +{ + if (name.empty()) + return; + + Gfx::Texture tex = GetTexture(name); + + if (tex.valid) + return; + + CImage img; + if (! img.Load(std::string("tex/") + name)) + { + std::string err = img.GetError(); + GetLogger()->Error("Texture not loaded, error: %s!\n", err.c_str()); + } + else + { + Gfx::TextureCreateParams texCreateParams; + texCreateParams.mipmap = true; + if (img.GetData()->surface->format->Amask == 0) + texCreateParams.format = Gfx::TEX_IMG_BGR; + else + texCreateParams.format = Gfx::TEX_IMG_BGRA; + texCreateParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR; + texCreateParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR; + + tex = device->CreateTexture(&img, texCreateParams); + } + + TEXS[name] = tex; +} + +void Init(Gfx::CGLDevice *device, Gfx::CModelFile *model) +{ + std::vector<Gfx::ModelTriangle> &triangles = model->GetTriangles(); + + for (int i = 0; i < (int) triangles.size(); ++i) + { + LoadTexture(device, triangles[i].tex1Name); + LoadTexture(device, triangles[i].tex2Name); + } + + device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true); + device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, true); + device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true); + device->SetShadeModel(Gfx::SHADE_SMOOTH); + + Gfx::Light light; + light.type = Gfx::LIGHT_DIRECTIONAL; + light.ambient = Gfx::Color(0.4f, 0.4f, 0.4f, 0.0f); + light.diffuse = Gfx::Color(0.8f, 0.8f, 0.8f, 0.0f); + light.specular = Gfx::Color(0.2f, 0.2f, 0.2f, 0.0f); + light.position = Math::Vector(0.0f, 0.0f, -1.0f); + light.direction = Math::Vector(0.0f, 0.0f, 1.0f); + + device->SetGlobalAmbient(Gfx::Color(0.5f, 0.5f, 0.5f, 0.0f)); + device->SetLight(0, light); + device->SetLightEnabled(0, true); +} + +void Render(Gfx::CGLDevice *device, Gfx::CModelFile *modelFile) +{ + device->BeginScene(); + + Math::Matrix persp; + Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 100.0f); + device->SetTransform(Gfx::TRANSFORM_PROJECTION, persp); + + Math::Matrix id; + id.LoadIdentity(); + device->SetTransform(Gfx::TRANSFORM_WORLD, id); + + Math::Matrix viewMat; + Math::LoadTranslationMatrix(viewMat, TRANSLATION); + Math::Matrix rot; + Math::LoadRotationXZYMatrix(rot, ROTATION); + viewMat = Math::MultiplyMatrices(viewMat, rot); + device->SetTransform(Gfx::TRANSFORM_VIEW, viewMat); + + std::vector<Gfx::ModelTriangle> &triangles = modelFile->GetTriangles(); + + Gfx::VertexTex2 tri[3]; + + for (int i = 0; i < (int) triangles.size(); ++i) + { + device->SetTexture(0, GetTexture(triangles[i].tex1Name)); + device->SetTexture(1, GetTexture(triangles[i].tex2Name)); + device->SetTextureEnabled(0, true); + device->SetTextureEnabled(1, true); + + device->SetMaterial(triangles[i].material); + + tri[0] = triangles[i].p1; + tri[1] = triangles[i].p2; + tri[2] = triangles[i].p3; + + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, tri, 3); + } + + device->EndScene(); +} + +void Update() +{ + const float ROT_SPEED = 80.0f * Math::DEG_TO_RAD; // rad / sec + const float TRANS_SPEED = 3.0f; // units / sec + + GetCurrentTimeStamp(CURR_TIME); + float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC); + CopyTimeStamp(PREV_TIME, CURR_TIME); + + if (KEYMAP[K_RotYLeft]) + ROTATION.y -= ROT_SPEED * timeDiff; + if (KEYMAP[K_RotYRight]) + ROTATION.y += ROT_SPEED * timeDiff; + if (KEYMAP[K_RotXDown]) + ROTATION.x -= ROT_SPEED * timeDiff; + if (KEYMAP[K_RotXUp]) + ROTATION.x += ROT_SPEED * timeDiff; + + if (KEYMAP[K_Forward]) + TRANSLATION.z -= TRANS_SPEED * timeDiff; + if (KEYMAP[K_Back]) + TRANSLATION.z += TRANS_SPEED * timeDiff; + if (KEYMAP[K_Left]) + TRANSLATION.x += TRANS_SPEED * timeDiff; + if (KEYMAP[K_Right]) + TRANSLATION.x -= TRANS_SPEED * timeDiff; + if (KEYMAP[K_Up]) + TRANSLATION.y += TRANS_SPEED * timeDiff; + if (KEYMAP[K_Down]) + TRANSLATION.y -= TRANS_SPEED * timeDiff; +} + +void KeyboardDown(SDLKey key) +{ + switch (key) + { + case SDLK_LEFT: + KEYMAP[K_RotYLeft] = true; + break; + case SDLK_RIGHT: + KEYMAP[K_RotYRight] = true; + break; + case SDLK_UP: + KEYMAP[K_RotXUp] = true; + break; + case SDLK_DOWN: + KEYMAP[K_RotXDown] = true; + break; + case SDLK_w: + KEYMAP[K_Forward] = true; + break; + case SDLK_s: + KEYMAP[K_Back] = true; + break; + case SDLK_a: + KEYMAP[K_Left] = true; + break; + case SDLK_d: + KEYMAP[K_Right] = true; + break; + case SDLK_z: + KEYMAP[K_Down] = true; + break; + case SDLK_x: + KEYMAP[K_Up] = true; + break; + default: + break; + } +} + +void KeyboardUp(SDLKey key) +{ + switch (key) + { + case SDLK_LEFT: + KEYMAP[K_RotYLeft] = false; + break; + case SDLK_RIGHT: + KEYMAP[K_RotYRight] = false; + break; + case SDLK_UP: + KEYMAP[K_RotXUp] = false; + break; + case SDLK_DOWN: + KEYMAP[K_RotXDown] = false; + break; + case SDLK_w: + KEYMAP[K_Forward] = false; + break; + case SDLK_s: + KEYMAP[K_Back] = false; + break; + case SDLK_a: + KEYMAP[K_Left] = false; + break; + case SDLK_d: + KEYMAP[K_Right] = false; + break; + case SDLK_z: + KEYMAP[K_Down] = false; + break; + case SDLK_x: + KEYMAP[K_Up] = false; + break; + default: + break; + } +} + +int main(int argc, char *argv[]) +{ + CLogger logger; + + PREV_TIME = CreateTimeStamp(); + CURR_TIME = CreateTimeStamp(); + + GetCurrentTimeStamp(PREV_TIME); + GetCurrentTimeStamp(CURR_TIME); + + if (argc != 3) + { + std::cerr << "Usage: " << argv[0] << "{mod|dxf} model_file" << std::endl; + return 1; + } + + CInstanceManager iMan; + + Gfx::CModelFile *modelFile = new Gfx::CModelFile(&iMan); + if (std::string(argv[1]) == "mod") + { + if (! modelFile->ReadModel(argv[2], false, false)) + { + std::cerr << "Error reading MOD: " << modelFile->GetError() << std::endl; + return 1; + } + } + else if (std::string(argv[1]) == "dxf") + { + if (! modelFile->ReadDXF(argv[2], 0.0f, 0.0f)) + { + std::cerr << "Error reading DXF: " << modelFile->GetError() << std::endl; + return 1; + } + } + else + { + std::cerr << "Usage: " << argv[0] << "{mod|dxf} model_file" << std::endl; + return 1; + } + + // Without any error checking, for simplicity + + SDL_Init(SDL_INIT_VIDEO); + + IMG_Init(IMG_INIT_PNG); + + const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); + + Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE; + + if (videoInfo->hw_available) + videoFlags |= SDL_HWSURFACE; + else + videoFlags |= SDL_SWSURFACE; + + if (videoInfo->blit_hw) + videoFlags |= SDL_HWACCEL; + + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8); + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags); + + + SDL_WM_SetCaption("Model Test", "Model Test"); + + Gfx::CGLDevice *device = new Gfx::CGLDevice(); + device->Create(); + + Init(device, modelFile); + + bool done = false; + while (! done) + { + Render(device, modelFile); + Update(); + + SDL_GL_SwapBuffers(); + + SDL_Event event; + SDL_PollEvent(&event); + if (event.type == SDL_QUIT) + done = true; + else if (event.type == SDL_KEYDOWN) + KeyboardDown(event.key.keysym.sym); + else if (event.type == SDL_KEYUP) + KeyboardUp(event.key.keysym.sym); + + usleep(FRAME_DELAY); + } + + delete modelFile; + + device->Destroy(); + delete device; + + SDL_FreeSurface(surface); + + IMG_Quit(); + + SDL_Quit(); + + DestroyTimeStamp(PREV_TIME); + DestroyTimeStamp(CURR_TIME); + + return 0; +} diff --git a/src/graphics/opengl/test/tex1.png b/src/graphics/opengl/test/tex1.png Binary files differnew file mode 100644 index 0000000..46c68a0 --- /dev/null +++ b/src/graphics/opengl/test/tex1.png diff --git a/src/graphics/opengl/test/tex2.png b/src/graphics/opengl/test/tex2.png Binary files differnew file mode 100644 index 0000000..ebdae0d --- /dev/null +++ b/src/graphics/opengl/test/tex2.png diff --git a/src/graphics/opengl/test/texture_test.cpp b/src/graphics/opengl/test/texture_test.cpp new file mode 100644 index 0000000..c3c568b --- /dev/null +++ b/src/graphics/opengl/test/texture_test.cpp @@ -0,0 +1,193 @@ +#include "common/logger.h" +#include "common/image.h" +#include "graphics/opengl/gldevice.h" +#include "math/geometry.h" + +#include <SDL/SDL.h> +#include <SDL/SDL_image.h> +#include <unistd.h> + + +void Init(Gfx::CGLDevice *device) +{ + device->SetShadeModel(Gfx::SHADE_SMOOTH); + + device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, false); + device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true); + + device->SetTextureEnabled(0, true); + device->SetTextureEnabled(1, true); + + CImage img1; + if (! img1.Load("tex1.png")) + { + std::string err = img1.GetError(); + GetLogger()->Error("texture 1 not loaded, error: %d!\n", err.c_str()); + } + CImage img2; + if (! img2.Load("tex2.png")) + { + std::string err = img2.GetError(); + GetLogger()->Error("texture 2 not loaded, error: %d!\n", err.c_str()); + } + + Gfx::TextureCreateParams tex1CreateParams; + tex1CreateParams.mipmap = true; + tex1CreateParams.format = Gfx::TEX_IMG_RGBA; + tex1CreateParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR; + tex1CreateParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR; + + Gfx::TextureCreateParams tex2CreateParams; + tex2CreateParams.mipmap = true; + tex2CreateParams.format = Gfx::TEX_IMG_RGBA; + tex2CreateParams.minFilter = Gfx::TEX_MIN_FILTER_NEAREST_MIPMAP_NEAREST; + tex2CreateParams.magFilter = Gfx::TEX_MAG_FILTER_NEAREST; + + Gfx::Texture tex1 = device->CreateTexture(&img1, tex1CreateParams); + Gfx::Texture tex2 = device->CreateTexture(&img2, tex2CreateParams); + + device->SetTexture(0, tex1); + device->SetTexture(1, tex2); +} + +void Render(Gfx::CGLDevice *device) +{ + device->BeginScene(); + + Math::Matrix ortho; + Math::LoadOrthoProjectionMatrix(ortho, -10, 10, -10, 10); + device->SetTransform(Gfx::TRANSFORM_PROJECTION, ortho); + + Math::Matrix id; + id.LoadIdentity(); + + device->SetTransform(Gfx::TRANSFORM_WORLD, id); + device->SetTransform(Gfx::TRANSFORM_VIEW, id); + + static Gfx::VertexTex2 quad[] = + { + Gfx::VertexTex2(Math::Vector(-2.0f, 2.0f, 0.0f), Math::Vector(), Math::Point(0.0f, 0.0f), Math::Point(0.0f, 0.0f)), + Gfx::VertexTex2(Math::Vector( 2.0f, 2.0f, 0.0f), Math::Vector(), Math::Point(1.0f, 0.0f), Math::Point(1.0f, 0.0f)), + Gfx::VertexTex2(Math::Vector( 2.0f, -2.0f, 0.0f), Math::Vector(), Math::Point(1.0f, 1.0f), Math::Point(1.0f, 1.0f)), + + Gfx::VertexTex2(Math::Vector( 2.0f, -2.0f, 0.0f), Math::Vector(), Math::Point(1.0f, 1.0f), Math::Point(1.0f, 1.0f)), + Gfx::VertexTex2(Math::Vector(-2.0f, -2.0f, 0.0f), Math::Vector(), Math::Point(0.0f, 1.0f), Math::Point(0.0f, 1.0f)), + Gfx::VertexTex2(Math::Vector(-2.0f, 2.0f, 0.0f), Math::Vector(), Math::Point(0.0f, 0.0f), Math::Point(0.0f, 0.0f)), + }; + + Gfx::TextureStageParams tex1StageParams; + tex1StageParams.colorOperation = Gfx::TEX_MIX_OPER_DEFAULT; + tex1StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; + device->SetTextureStageParams(0, tex1StageParams); + + Gfx::TextureStageParams tex2StageParams; + tex2StageParams.colorOperation = Gfx::TEX_MIX_OPER_DEFAULT; + tex2StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; + device->SetTextureStageParams(1, tex2StageParams); + + Math::Matrix t; + Math::LoadTranslationMatrix(t, Math::Vector(-4.0f, 4.0f, 0.0f)); + device->SetTransform(Gfx::TRANSFORM_VIEW, t); + + device->SetTextureEnabled(0, true); + device->SetTextureEnabled(1, false); + + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6); + + Math::LoadTranslationMatrix(t, Math::Vector( 4.0f, 4.0f, 0.0f)); + device->SetTransform(Gfx::TRANSFORM_VIEW, t); + + device->SetTextureEnabled(0, false); + device->SetTextureEnabled(1, true); + + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6); + + Math::LoadTranslationMatrix(t, Math::Vector( 0.0f, -4.0f, 0.0f)); + device->SetTransform(Gfx::TRANSFORM_VIEW, t); + + device->SetTextureEnabled(0, true); + device->SetTextureEnabled(1, true); + + tex1StageParams.colorOperation = Gfx::TEX_MIX_OPER_DEFAULT; + tex1StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; + device->SetTextureStageParams(0, tex1StageParams); + + tex2StageParams.colorOperation = Gfx::TEX_MIX_OPER_ADD; + tex2StageParams.colorArg1 = Gfx::TEX_MIX_ARG_COMPUTED_COLOR; + tex2StageParams.colorArg2 = Gfx::TEX_MIX_ARG_TEXTURE; + tex2StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT; + device->SetTextureStageParams(1, tex2StageParams); + + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6); + + device->EndScene(); +} + +int main() +{ + CLogger(); + + // Without any error checking, for simplicity + + SDL_Init(SDL_INIT_VIDEO); + + IMG_Init(IMG_INIT_PNG); + + const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); + + Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE; + + if (videoInfo->hw_available) + videoFlags |= SDL_HWSURFACE; + else + videoFlags |= SDL_SWSURFACE; + + if (videoInfo->blit_hw) + videoFlags |= SDL_HWACCEL; + + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8); + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags); + + + SDL_WM_SetCaption("Texture Test", "Texture Test"); + + Gfx::CGLDevice *device = new Gfx::CGLDevice(); + device->Create(); + + Init(device); + + bool done = false; + while (! done) + { + Render(device); + + SDL_GL_SwapBuffers(); + + SDL_Event event; + SDL_PollEvent(&event); + if (event.type == SDL_QUIT) + done = true; + + usleep(10000); + } + + device->Destroy(); + delete device; + + SDL_FreeSurface(surface); + + IMG_Quit(); + + SDL_Quit(); + + return 0; +} diff --git a/src/graphics/opengl/test/transform_test.cpp b/src/graphics/opengl/test/transform_test.cpp new file mode 100644 index 0000000..83819b8 --- /dev/null +++ b/src/graphics/opengl/test/transform_test.cpp @@ -0,0 +1,339 @@ +#include "app/system.h" +#include "common/logger.h" +#include "common/image.h" +#include "common/iman.h" +#include "graphics/opengl/gldevice.h" +#include "math/geometry.h" + +#include <SDL/SDL.h> +#include <SDL/SDL_image.h> +#include <unistd.h> + +#include <iostream> +#include <map> + +enum KeySlots +{ + K_Forward, + K_Back, + K_Left, + K_Right, + K_Up, + K_Down, + K_Count +}; +bool KEYMAP[K_Count] = { false }; + +Math::Point MOUSE_POS_BASE; + +Math::Vector TRANSLATION(0.0f, 2.0f, 0.0f); +Math::Vector ROTATION, ROTATION_BASE; + +const int FRAME_DELAY = 5000; + +SystemTimeStamp *PREV_TIME = NULL, *CURR_TIME = NULL; + +void Init(Gfx::CGLDevice *device) +{ + device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true); + device->SetShadeModel(Gfx::SHADE_SMOOTH); +} + +void Render(Gfx::CGLDevice *device) +{ + device->BeginScene(); + + Math::Matrix persp; + Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 100.0f); + device->SetTransform(Gfx::TRANSFORM_PROJECTION, persp); + + + Math::Matrix viewMat; + Math::Matrix mat; + + viewMat.LoadIdentity(); + + Math::LoadRotationXMatrix(mat, -ROTATION.x); + viewMat = Math::MultiplyMatrices(viewMat, mat); + + Math::LoadRotationYMatrix(mat, -ROTATION.y); + viewMat = Math::MultiplyMatrices(viewMat, mat); + + Math::LoadTranslationMatrix(mat, -TRANSLATION); + viewMat = Math::MultiplyMatrices(viewMat, mat); + + device->SetTransform(Gfx::TRANSFORM_VIEW, viewMat); + + + Math::Matrix worldMat; + worldMat.LoadIdentity(); + device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat); + + Gfx::VertexCol line[2] = { Gfx::VertexCol() }; + + for (int x = -40; x <= 40; ++x) + { + line[0].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f); + line[0].coord.z = -40; + line[0].coord.x = x; + line[1].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f); + line[1].coord.z = 40; + line[1].coord.x = x; + device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2); + } + + for (int z = -40; z <= 40; ++z) + { + line[0].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f); + line[0].coord.z = z; + line[0].coord.x = -40; + line[1].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f); + line[1].coord.z = z; + line[1].coord.x = 40; + device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2); + } + + + Gfx::VertexCol quad[6] = { Gfx::VertexCol() }; + + for (int i = 0; i < 6; ++i) + quad[i].color = Gfx::Color(1.0f, 1.0f, 0.0f); + + quad[0].coord = Math::Vector(-1.0f, -1.0f, 0.0f); + quad[1].coord = Math::Vector( 1.0f, -1.0f, 0.0f); + quad[2].coord = Math::Vector( 1.0f, 1.0f, 0.0f); + quad[3].coord = Math::Vector( 1.0f, 1.0f, 0.0f); + quad[4].coord = Math::Vector(-1.0f, 1.0f, 0.0f); + quad[5].coord = Math::Vector(-1.0f, -1.0f, 0.0f); + + Math::LoadTranslationMatrix(worldMat, Math::Vector(40.0f, 2.0f, 40.0f)); + device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat); + + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6); + + for (int i = 0; i < 6; ++i) + quad[i].color = Gfx::Color(0.0f, 1.0f, 1.0f); + + Math::LoadTranslationMatrix(worldMat, Math::Vector(-40.0f, 2.0f, -40.0f)); + device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat); + + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6); + + for (int i = 0; i < 6; ++i) + quad[i].color = Gfx::Color(1.0f, 0.0f, 1.0f); + + Math::LoadTranslationMatrix(worldMat, Math::Vector(0.0f, 10.0f, 0.0f)); + device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat); + + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6); + + device->EndScene(); +} + +void Update() +{ + const float TRANS_SPEED = 6.0f; // units / sec + + GetCurrentTimeStamp(CURR_TIME); + float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC); + CopyTimeStamp(PREV_TIME, CURR_TIME); + + Math::Vector incTrans; + + if (KEYMAP[K_Forward]) + incTrans.z = +TRANS_SPEED * timeDiff; + if (KEYMAP[K_Back]) + incTrans.z = -TRANS_SPEED * timeDiff; + if (KEYMAP[K_Right]) + incTrans.x = +TRANS_SPEED * timeDiff; + if (KEYMAP[K_Left]) + incTrans.x = -TRANS_SPEED * timeDiff; + if (KEYMAP[K_Up]) + incTrans.y = +TRANS_SPEED * timeDiff; + if (KEYMAP[K_Down]) + incTrans.y = -TRANS_SPEED * timeDiff; + + Math::Point rotTrans = Math::RotatePoint(-ROTATION.y, Math::Point(incTrans.x, incTrans.z)); + incTrans.x = rotTrans.x; + incTrans.z = rotTrans.y; + TRANSLATION += incTrans; +} + +void KeyboardDown(SDLKey key) +{ + switch (key) + { + case SDLK_w: + KEYMAP[K_Forward] = true; + break; + case SDLK_s: + KEYMAP[K_Back] = true; + break; + case SDLK_d: + KEYMAP[K_Right] = true; + break; + case SDLK_a: + KEYMAP[K_Left] = true; + break; + case SDLK_z: + KEYMAP[K_Down] = true; + break; + case SDLK_x: + KEYMAP[K_Up] = true; + break; + default: + break; + } +} + +void KeyboardUp(SDLKey key) +{ + switch (key) + { + case SDLK_w: + KEYMAP[K_Forward] = false; + break; + case SDLK_s: + KEYMAP[K_Back] = false; + break; + case SDLK_d: + KEYMAP[K_Right] = false; + break; + case SDLK_a: + KEYMAP[K_Left] = false; + break; + case SDLK_z: + KEYMAP[K_Down] = false; + break; + case SDLK_x: + KEYMAP[K_Up] = false; + break; + default: + break; + } +} + +void MouseMove(int x, int y) +{ + Math::Point currentPos((float)x, (float)y); + + static bool first = true; + if (first || (x < 10) || (y < 10) || (x > 790) || (y > 590)) + { + SDL_WarpMouse(400, 300); + MOUSE_POS_BASE.x = 400; + MOUSE_POS_BASE.y = 300; + ROTATION_BASE = ROTATION; + first = false; + return; + } + + ROTATION.y = ROTATION_BASE.y + ((float) (x - MOUSE_POS_BASE.x) / 800.0f) * Math::PI; + ROTATION.x = ROTATION_BASE.x + ((float) (y - MOUSE_POS_BASE.y) / 600.0f) * Math::PI; +} + +int main(int argc, char *argv[]) +{ + CLogger logger; + + PREV_TIME = CreateTimeStamp(); + CURR_TIME = CreateTimeStamp(); + + GetCurrentTimeStamp(PREV_TIME); + GetCurrentTimeStamp(CURR_TIME); + + CInstanceManager iMan; + + // Without any error checking, for simplicity + + SDL_Init(SDL_INIT_VIDEO); + + IMG_Init(IMG_INIT_PNG); + + const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); + + Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE; + + if (videoInfo->hw_available) + videoFlags |= SDL_HWSURFACE; + else + videoFlags |= SDL_SWSURFACE; + + if (videoInfo->blit_hw) + videoFlags |= SDL_HWACCEL; + + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8); + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags); + + + SDL_WM_SetCaption("Transform Test", "Transform Test"); + + //SDL_WM_GrabInput(SDL_GRAB_ON); + SDL_ShowCursor(SDL_DISABLE); + + Gfx::CGLDevice *device = new Gfx::CGLDevice(); + device->Create(); + + Init(device); + + bool done = false; + while (! done) + { + Render(device); + Update(); + + SDL_GL_SwapBuffers(); + + SDL_Event event; + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT) + { + break; + done = true; + } + else if (event.type == SDL_KEYDOWN) + { + if (event.key.keysym.sym == SDLK_q) + { + done = true; + break; + } + else + KeyboardDown(event.key.keysym.sym); + } + else if (event.type == SDL_KEYUP) + KeyboardUp(event.key.keysym.sym); + else if (event.type == SDL_MOUSEMOTION) + MouseMove(event.motion.x, event.motion.y); + } + + usleep(FRAME_DELAY); + } + + //SDL_WM_GrabInput(SDL_GRAB_OFF); + SDL_ShowCursor(SDL_ENABLE); + + device->Destroy(); + delete device; + + SDL_FreeSurface(surface); + + IMG_Quit(); + + SDL_Quit(); + + DestroyTimeStamp(PREV_TIME); + DestroyTimeStamp(CURR_TIME); + + return 0; +} |