Ticket #824: pretty_unit_rings_WIP_01mar12.patch
File pretty_unit_rings_WIP_01mar12.patch, 97.2 KB (added by , 12 years ago) |
---|
-
new file inaries/data/mods/public/shaders/overlay_selection.fp
diff --git a/binaries/data/mods/public/shaders/overlay_selection.fp b/binaries/data/mods/public/shaders/overlay_selection.fp new file mode 100644 index 0000000..f6c5708
- + 1 !!ARBfp1.0 2 TEMP base; 3 TEMP mask; 4 TEMP color; 5 6 // Combine base texture and color, using mask texture 7 TEX base, fragment.texcoord[0], texture[0], 2D; 8 TEX mask, fragment.texcoord[0], texture[1], 2D; 9 LRP color.rgb, mask, fragment.color, base; 10 11 // Multiply RGB by LOS texture (alpha channel) 12 TEMP los; 13 TEX los, fragment.texcoord[1], texture[2], 2D; 14 MUL result.color.rgb, color, los.a; 15 16 // Use alpha from base texture, combined with the object color alpha. 17 MUL result.color.a, fragment.color.a, base.a; 18 19 END -
new file inaries/data/mods/public/shaders/overlay_selection.vp
diff --git a/binaries/data/mods/public/shaders/overlay_selection.vp b/binaries/data/mods/public/shaders/overlay_selection.vp new file mode 100644 index 0000000..b4a9abb
- + 1 !!ARBvp1.0 2 PARAM losTransform = program.local[0]; 3 ATTRIB position = vertex.position; 4 5 DP4 result.position.x, state.matrix.mvp.row[0], position; 6 DP4 result.position.y, state.matrix.mvp.row[1], position; 7 DP4 result.position.z, state.matrix.mvp.row[2], position; 8 DP4 result.position.w, state.matrix.mvp.row[3], position; 9 10 MOV result.texcoord[0], vertex.texcoord[0]; 11 MAD result.texcoord[1], position.xzzz, losTransform.x, losTransform.y; 12 13 MOV result.color, vertex.color; 14 15 END -
new file inaries/data/mods/public/shaders/overlay_selection.xml
diff --git a/binaries/data/mods/public/shaders/overlay_selection.xml b/binaries/data/mods/public/shaders/overlay_selection.xml new file mode 100644 index 0000000..7cf03e6
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 <program type="arb"> 3 4 <vertex file="overlay_selection.vp"> 5 <stream name="pos"/> 6 <stream name="uv0"/> 7 <stream name="color"/> 8 <uniform name="losTransform" loc="0" type="vec2"/> 9 </vertex> 10 11 <fragment file="overlay_selection.fp"> 12 <uniform name="baseTex" loc="0" type="sampler2D"/> 13 <uniform name="maskTex" loc="1" type="sampler2D"/> 14 <uniform name="losTex" loc="2" type="sampler2D"/> 15 </fragment> 16 17 </program> -
binaries/data/mods/public/simulation/components/GuiInterface.js
diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js index 16ee222..c7fdb51 100644
a b GuiInterface.prototype.IsStanceSelected = function(player, data) 375 375 GuiInterface.prototype.SetSelectionHighlight = function(player, cmd) 376 376 { 377 377 var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 378 379 378 var playerColours = {}; // cache of owner -> colour map 380 379 381 380 for each (var ent in cmd.entities) … … GuiInterface.prototype.SetSelectionHighlight = function(player, cmd) 384 383 if (!cmpSelectable) 385 384 continue; 386 385 387 if (cmd.alpha == 0)388 {389 cmpSelectable.SetSelectionHighlight({"r":0, "g":0, "b":0, "a":0});390 continue;391 }392 393 386 // Find the entity's owner's colour: 394 395 387 var owner = -1; 396 388 var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); 397 389 if (cmpOwnership) -
binaries/data/mods/public/simulation/templates/special/territory_block.xml
diff --git a/binaries/data/mods/public/simulation/templates/special/territory_block.xml b/binaries/data/mods/public/simulation/templates/special/territory_block.xml index 52432b2..f0893a0 100644
a b 23 23 </Position> 24 24 <Selectable> 25 25 <EditorOnly disable=""/> 26 <Overlay> 27 <Texture> 28 <MainTexture>art/textures/selection/circle/64x64.png</MainTexture> 29 <MainTextureMask>art/textures/selection/circle/64x64_mask.png</MainTextureMask> 30 </Texture> 31 </Overlay> 26 32 </Selectable> 27 33 <TerritoryInfluence> 28 34 <OverrideCost>64</OverrideCost> -
binaries/data/mods/public/simulation/templates/special/territory_pull.xml
diff --git a/binaries/data/mods/public/simulation/templates/special/territory_pull.xml b/binaries/data/mods/public/simulation/templates/special/territory_pull.xml index bd8c4ac..a12174a 100644
a b 23 23 </Position> 24 24 <Selectable> 25 25 <EditorOnly disable=""/> 26 <Overlay> 27 <Texture> 28 <MainTexture>art/textures/selection/circle/64x64.png</MainTexture> 29 <MainTextureMask>art/textures/selection/circle/64x64_mask.png</MainTextureMask> 30 </Texture> 31 </Overlay> 26 32 </Selectable> 27 33 <TerritoryInfluence> 28 34 <OverrideCost>0</OverrideCost> -
binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml b/binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml index e979c8e..775f6e0 100644
a b 18 18 </ResourceSupply> 19 19 <Selectable> 20 20 <EditorOnly disable=""/> 21 <Overlay> 22 <Texture> 23 <MainTexture>art/textures/selection/circle/64x64.png</MainTexture> 24 <MainTextureMask>art/textures/selection/circle/64x64_mask.png</MainTextureMask> 25 </Texture> 26 </Overlay> 21 27 </Selectable> 22 28 <Sound> 23 29 <SoundGroups> -
binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml b/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml index ca3e80f..d5ba7d7 100644
a b 17 17 </ResourceSupply> 18 18 <Selectable> 19 19 <EditorOnly disable=""/> 20 <Overlay> 21 <Texture> 22 <MainTexture>art/textures/selection/circle/64x64.png</MainTexture> 23 <MainTextureMask>art/textures/selection/circle/64x64_mask.png</MainTextureMask> 24 </Texture> 25 </Overlay> 20 26 </Selectable> 21 27 <Sound> 22 28 <SoundGroups> -
binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral.xml b/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral.xml index f3a147a..d04ad80 100644
a b 17 17 </ResourceSupply> 18 18 <Selectable> 19 19 <EditorOnly disable=""/> 20 <Overlay> 21 <Outline> 22 <LineTexture>art/textures/selection/outline_border.png</LineTexture> 23 <LineTextureMask>art/textures/selection/outline_border_mask.png</LineTextureMask> 24 <LineThickness>0.2</LineThickness> 25 </Outline> 26 </Overlay> 20 27 </Selectable> 21 28 <Sound> 22 29 <SoundGroups> -
binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml b/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml index a954293..b0cf874 100644
a b 17 17 </ResourceSupply> 18 18 <Selectable> 19 19 <EditorOnly disable=""/> 20 <Overlay> 21 <Texture> 22 <MainTexture>art/textures/selection/circle/64x64.png</MainTexture> 23 <MainTextureMask>art/textures/selection/circle/64x64_mask.png</MainTextureMask> 24 </Texture> 25 </Overlay> 20 26 </Selectable> 21 27 <Sound> 22 28 <SoundGroups> -
binaries/data/mods/public/simulation/templates/template_gaia_ruins.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_ruins.xml b/binaries/data/mods/public/simulation/templates/template_gaia_ruins.xml index 86037bb..2b256cc 100644
a b 24 24 </ResourceSupply> 25 25 <Selectable> 26 26 <EditorOnly disable=""/> 27 <Overlay> 28 <Texture> 29 <MainTexture>art/textures/selection/circle/64x64.png</MainTexture> 30 <MainTextureMask>art/textures/selection/circle/64x64_mask.png</MainTextureMask> 31 </Texture> 32 </Overlay> 27 33 </Selectable> 28 34 </Entity> -
binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml b/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml index cb45f0a..b2744f4 100644
a b 24 24 </ResourceSupply> 25 25 <Selectable> 26 26 <EditorOnly disable=""/> 27 <Overlay> 28 <Texture> 29 <MainTexture>art/textures/selection/circle/64x64.png</MainTexture> 30 <MainTextureMask>art/textures/selection/circle/64x64_mask.png</MainTextureMask> 31 </Texture> 32 </Overlay> 27 33 </Selectable> 28 34 </Entity> -
binaries/data/mods/public/simulation/templates/template_structure.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_structure.xml b/binaries/data/mods/public/simulation/templates/template_structure.xml index d876613..a5a9827 100644
a b 66 66 <LineCostClass>default</LineCostClass> 67 67 <LinePassabilityClass>default</LinePassabilityClass> 68 68 </RallyPointRenderer> 69 <Selectable> 70 <Overlay> 71 <Outline> 72 <LineTexture>art/textures/selection/outline_border.png</LineTexture> 73 <LineTextureMask>art/textures/selection/outline_border_mask.png</LineTextureMask> 74 <LineThickness>0.4</LineThickness> 75 </Outline> 76 </Overlay> 77 </Selectable> 69 78 <Sound> 70 79 <SoundGroups> 71 80 <select>interface/select/building/sel_universal.xml</select> -
binaries/data/mods/public/simulation/templates/template_unit.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_unit.xml b/binaries/data/mods/public/simulation/templates/template_unit.xml index d524a39..20c9d38 100644
a b 80 80 <metal>20</metal> 81 81 </Capacities> 82 82 </ResourceGatherer> 83 <Selectable> 84 <Overlay> 85 <Texture> 86 <MainTexture>art/textures/selection/circle/64x64.png</MainTexture> 87 <MainTextureMask>art/textures/selection/circle/64x64_mask.png</MainTextureMask> 88 </Texture> 89 </Overlay> 90 </Selectable> 83 91 <StatusBars> 84 92 <BarWidth>2.0</BarWidth> 85 93 <BarHeight>0.333</BarHeight> -
source/graphics/ModelAbstract.h
diff --git a/binaries/system/ActorEditor.exe b/binaries/system/ActorEditor.exe deleted file mode 100644 index 15cdfc5..0000000 Binary files a/binaries/system/ActorEditor.exe and /dev/null differ diff --git a/source/graphics/ModelAbstract.h b/source/graphics/ModelAbstract.h index 1686847..60baec3 100644
a b public: 89 89 virtual void SetDirtyRec(int dirtyflags) = 0; 90 90 91 91 /// Returns world space bounds of this object and all child objects. 92 virtual const CBoundingBoxAligned GetWorldBoundsRec() { return GetWorldBounds(); } 92 virtual const CBoundingBoxAligned GetWorldBoundsRec() { return GetWorldBounds(); } // default implementation 93 93 94 94 /** 95 95 * Returns the world-space selection box of this model. Used primarily for hittesting against against a selection ray. The -
source/graphics/Overlay.h
diff --git a/source/graphics/Overlay.h b/source/graphics/Overlay.h index ce6f7c4..7af3282 100644
a b 18 18 #ifndef INCLUDED_GRAPHICS_OVERLAY 19 19 #define INCLUDED_GRAPHICS_OVERLAY 20 20 21 #include "precompiled.h" 22 23 #include "lib/ogl.h" 21 24 #include "graphics/RenderableObject.h" 22 25 #include "graphics/Texture.h" 26 #include "maths/Vector2D.h" 23 27 #include "maths/Vector3D.h" 24 28 #include "ps/Overlay.h" // CColor (TODO: that file has nothing to do with overlays, it should be renamed) 29 #include "simulation2/components/ICmpFootprint.h" 25 30 26 31 class CTerrain; 27 32 … … struct SOverlayLine 37 42 std::vector<float> m_Coords; // (x, y, z) vertex coordinate triples; shape is not automatically closed 38 43 u8 m_Thickness; // pixels 39 44 40 /// Utility function; pushes three vertex coordinates at once onto the coordinates array41 45 void PushCoords(const float x, const float y, const float z) { m_Coords.push_back(x); m_Coords.push_back(y); m_Coords.push_back(z); } 42 /// Utility function; pushes a vertex location onto the coordinates array43 46 void PushCoords(const CVector3D& v) { PushCoords(v.X, v.Y, v.Z); } 44 47 }; 45 48 … … struct SOverlayTexturedLine 64 67 }; 65 68 66 69 SOverlayTexturedLine() 67 : m_Terrain(NULL), m_Thickness(1.0f), m_Closed(false), m_AlwaysVisible(false), m_StartCapType(LINECAP_FLAT), m_EndCapType(LINECAP_FLAT) 68 {} 70 : m_SimContext(NULL), m_Thickness(1.0f), m_Closed(false), m_AlwaysVisible(false), 71 m_StartCapType(LINECAP_FLAT), m_EndCapType(LINECAP_FLAT) 72 { } 69 73 70 CTerrain* m_Terrain;71 74 CTexturePtr m_TextureBase; 72 75 CTexturePtr m_TextureMask; 73 76 CColor m_Color; ///< Color to apply to the line texture … … struct SOverlayTexturedLine 79 82 LineCapType m_StartCapType; ///< LineCapType to be used at the start of the line 80 83 LineCapType m_EndCapType; ///< LineCapType to be used at the end of the line 81 84 85 const CSimContext* m_SimContext; /// Simulation context applicable for this overlay line; used to obtain terrain information 82 86 shared_ptr<CRenderData> m_RenderData; ///< Cached renderer data (shared_ptr so that copies/deletes are automatic) 83 87 84 88 /** … … struct SOverlayTexturedLine 86 90 * If the input string is unrecognized, a warning is issued and a default value is returned. 87 91 */ 88 92 static LineCapType StrToLineCapType(const std::wstring& str); 93 94 void PushCoords(const float x, const float z) { m_Coords.push_back(x); m_Coords.push_back(z); } 95 void PushCoords(const CVector2D& v) { PushCoords(v.X, v.Y); } 96 void PushCoords(const std::vector<CVector2D>& points) 97 { 98 for (std::size_t i = 0; i < points.size(); ++i) 99 PushCoords(points[i]); 100 } 89 101 }; 90 102 91 103 /** … … struct SOverlaySprite 99 111 float m_X0, m_Y0, m_X1, m_Y1; // billboard corner coordinates, relative to base position 100 112 }; 101 113 114 /** 115 * Rectangular single-quad terrain overlay, with world space coordinates. 116 */ 117 struct SOverlayQuad 118 { 119 CTexturePtr m_Texture; 120 CTexturePtr m_TextureMask; 121 CVector3D m_Corners[4]; 122 CColor m_Color; 123 }; 124 102 125 // TODO: OverlayText 103 126 104 127 #endif // INCLUDED_GRAPHICS_OVERLAY -
source/graphics/RenderableObject.h
diff --git a/source/graphics/RenderableObject.h b/source/graphics/RenderableObject.h index c3784fd..01bb923 100644
a b class CRenderableObject 57 57 58 58 public: 59 59 // constructor 60 CRenderableObject() : m_RenderData(0), m_BoundsValid(false) { 60 CRenderableObject() : m_RenderData(0), m_BoundsValid(false) 61 { 61 62 m_Transform.SetIdentity(); 62 63 } 63 64 // destructor 64 65 virtual ~CRenderableObject() { delete m_RenderData; } 65 66 66 67 // set object transform 67 virtual void SetTransform(const CMatrix3D& transform) { 68 virtual void SetTransform(const CMatrix3D& transform) 69 { 68 70 if (m_Transform == transform) 69 71 return; 70 72 // store transform, calculate inverse … … public: 82 84 83 85 // mark some part of the renderdata as dirty, and requiring 84 86 // an update on next render 85 void SetDirty(u32 dirtyflags) { 86 if (m_RenderData) m_RenderData->m_UpdateFlags|=dirtyflags; 87 void SetDirty(u32 dirtyflags) 88 { 89 if (m_RenderData) 90 m_RenderData->m_UpdateFlags |= dirtyflags; 87 91 } 88 92 89 93 /** … … public: 98 102 virtual void CalcBounds() = 0; 99 103 100 104 /// Returns the world-space axis-aligned bounds of this object. 101 const CBoundingBoxAligned& GetWorldBounds() { 105 const CBoundingBoxAligned& GetWorldBounds() 106 { 102 107 RecalculateBoundsIfNecessary(); 103 108 return m_WorldBounds; 104 109 } … … public: 111 116 virtual void InvalidateBounds() { m_BoundsValid = false; } 112 117 113 118 // Set the object renderdata and free previous renderdata, if any. 114 void SetRenderData(CRenderData* renderdata) { 119 void SetRenderData(CRenderData* renderdata) 120 { 115 121 delete m_RenderData; 116 122 m_RenderData = renderdata; 117 123 } -
source/maths/FixedVector2D.h
diff --git a/source/maths/FixedVector2D.h b/source/maths/FixedVector2D.h index c58f66f..739469e 100644
a b public: 27 27 fixed X, Y; 28 28 29 29 CFixedVector2D() { } 30 31 30 CFixedVector2D(fixed X, fixed Y) : X(X), Y(Y) { } 32 31 33 32 /// Vector equality -
source/maths/MathUtil.h
diff --git a/source/maths/MathUtil.h b/source/maths/MathUtil.h index 741e57e..b00a70b 100644
a b 18 18 #ifndef INCLUDED_MATHUTIL 19 19 #define INCLUDED_MATHUTIL 20 20 21 #include <cmath> 22 21 23 #define DEGTORAD(a) ((a) * ((float)M_PI/180.0f)) 22 24 #define RADTODEG(a) ((a) * (180.0f/(float)M_PI)) 23 25 #define SQR(x) ((x) * (x)) -
source/maths/Vector2D.h
diff --git a/source/maths/Vector2D.h b/source/maths/Vector2D.h index 977584c..55787d8 100644
a b public: 121 121 Y /= mag; 122 122 } 123 123 124 CVector2D Normalized() 124 CVector2D Normalized() const 125 125 { 126 126 float mag = Length(); 127 127 return CVector2D(X / mag, Y / mag); … … public: 130 130 /** 131 131 * Returns a version of this vector rotated counterclockwise by @p angle radians. 132 132 */ 133 CVector2D Rotated(float angle) 133 CVector2D Rotated(float angle) const 134 134 { 135 135 float c = cosf(angle); 136 136 float s = sinf(angle); -
source/renderer/OverlayRenderer.cpp
diff --git a/source/renderer/OverlayRenderer.cpp b/source/renderer/OverlayRenderer.cpp index 938574c..9382ec0 100644
a b 19 19 20 20 #include "OverlayRenderer.h" 21 21 22 #include "maths/MathUtil.h" 23 #include "maths/Quaternion.h" 24 #include "maths/Vector2D.h" 22 #include "boost/unordered_map.hpp" 25 23 #include "graphics/LOSTexture.h" 26 24 #include "graphics/Overlay.h" 27 25 #include "graphics/Terrain.h" 28 26 #include "graphics/TextureManager.h" 29 27 #include "lib/ogl.h" 28 #include "maths/MathUtil.h" 29 #include "maths/Quaternion.h" 30 30 #include "ps/Game.h" 31 31 #include "ps/Profile.h" 32 32 #include "renderer/Renderer.h" … … 34 34 #include "renderer/VertexBufferManager.h" 35 35 #include "simulation2/Simulation2.h" 36 36 #include "simulation2/components/ICmpWaterManager.h" 37 #include "simulation2/system/SimContext.h" 38 39 const float OverlayRenderer::OVERLAY_VOFFSET = 0.2f; 40 41 struct QuadBatchKey 42 { 43 QuadBatchKey (CTexturePtr texture, CTexturePtr textureMask) : m_Texture(texture), m_TextureMask(textureMask){ } 44 45 struct hash : std::unary_function<QuadBatchKey, size_t> { 46 size_t operator()(const QuadBatchKey& d) const; 47 }; 48 49 struct eq : std::binary_function<QuadBatchKey, QuadBatchKey, bool> { 50 bool operator()(const QuadBatchKey& d1, const QuadBatchKey& d2) const; 51 }; 52 53 CTexturePtr m_Texture; 54 CTexturePtr m_TextureMask; 55 }; 56 57 class QuadBatchData : public CRenderData 58 { 59 public: 60 struct SVertex 61 { 62 SVertex(const CVector3D& pos, GLshort u, GLshort v, const CColor& color) : m_Position(pos), m_Color(color) 63 { m_UVs[0] = u; m_UVs[1] = v; } 64 65 CVector3D m_Position; 66 GLshort m_UVs[2]; 67 CColor m_Color; 68 }; 69 cassert(sizeof(SVertex) == 32); 70 71 QuadBatchData() : m_VB(NULL), m_VBIndices(NULL) { } 72 ~QuadBatchData() 73 { 74 // TODO: gets called by boost::unordered_map during PrepareForRendering, not desirable 75 if (m_VB) 76 g_VBMan.Release(m_VB); 77 if (m_VBIndices) 78 g_VBMan.Release(m_VBIndices); 79 } 80 81 std::vector<SOverlayQuad*> m_Quads; 82 CVertexBuffer::VBChunk* m_VB; 83 CVertexBuffer::VBChunk* m_VBIndices; 84 }; 37 85 38 86 struct OverlayRendererInternals 39 87 { 88 typedef boost::unordered_map<QuadBatchKey, QuadBatchData, QuadBatchKey::hash, QuadBatchKey::eq> QuadBatchMap; 89 40 90 std::vector<SOverlayLine*> lines; 41 91 std::vector<SOverlayTexturedLine*> texlines; 42 92 std::vector<SOverlaySprite*> sprites; 93 std::vector<SOverlayQuad*> quads; 94 95 QuadBatchMap quadBatchData; 43 96 }; 44 97 45 98 class CTexturedLineRData : public CRenderData 46 99 { 47 100 public: 48 CTexturedLineRData(SOverlayTexturedLine* line) : 49 m_Line(line), m_VB(NULL), m_VBIndices(NULL), m_Raise(.2f) 101 CTexturedLineRData(SOverlayTexturedLine* line) : m_Line(line), m_VB(NULL), m_VBIndices(NULL) 50 102 { } 51 103 52 104 ~CTexturedLineRData() … … public: 62 114 SVertex(CVector3D pos, float u, float v) : m_Position(pos) { m_UVs[0] = u; m_UVs[1] = v; } 63 115 CVector3D m_Position; 64 116 GLfloat m_UVs[2]; 65 float _padding[3]; // 5 floats up till now, so pad with another 3 floats to get a power of 2117 float _padding[3]; // get a pow2 struct size 66 118 }; 67 119 cassert(sizeof(SVertex) == 32); 68 120 … … public: 91 143 SOverlayTexturedLine* m_Line; 92 144 CVertexBuffer::VBChunk* m_VB; 93 145 CVertexBuffer::VBChunk* m_VBIndices; 94 95 float m_Raise; // small vertical offset of line from terrain to prevent visual glitches96 146 }; 97 147 98 148 OverlayRenderer::OverlayRenderer() … … void OverlayRenderer::Submit(SOverlaySprite* overlay) 128 178 m->sprites.push_back(overlay); 129 179 } 130 180 181 void OverlayRenderer::Submit(SOverlayQuad* overlay) 182 { 183 m->quads.push_back(overlay); 184 } 185 131 186 void OverlayRenderer::EndFrame() 132 187 { 133 188 m->lines.clear(); 134 189 m->texlines.clear(); 135 190 m->sprites.clear(); 191 m->quads.clear(); 136 192 // this should leave the capacity unchanged, which is okay since it 137 193 // won't be very large or very variable 194 195 // empty the batch rendering data structures, but keep their key mappings around for the next frames 196 for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchData.begin(); it != m->quadBatchData.end(); it++) 197 { 198 QuadBatchData& batchRenderData = (it->second); 199 200 batchRenderData.m_Quads.clear(); 201 if (batchRenderData.m_VB) 202 { 203 g_VBMan.Release(batchRenderData.m_VB); 204 batchRenderData.m_VB = NULL; 205 } 206 if (batchRenderData.m_VBIndices) 207 { 208 g_VBMan.Release(batchRenderData.m_VBIndices); 209 batchRenderData.m_VBIndices = NULL; 210 } 211 } 138 212 } 139 213 140 214 void OverlayRenderer::PrepareForRendering() … … void OverlayRenderer::PrepareForRendering() 157 231 // any of the parameters after first submitting the line. 158 232 } 159 233 } 234 235 // group quad overlays by their texture/mask combination for efficient rendering 236 for (size_t i = 0; i < m->quads.size(); ++i) 237 { 238 SOverlayQuad* const quad = m->quads[i]; 239 240 QuadBatchKey textures(quad->m_Texture, quad->m_TextureMask); 241 QuadBatchData& batchRenderData = m->quadBatchData[textures]; // will create entry if it doesn't already exist 242 243 // add overlay to list of quads 244 batchRenderData.m_Quads.push_back(quad); 245 } 246 247 // Add vertices 248 for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchData.begin(); it != m->quadBatchData.end(); ++it) 249 { 250 QuadBatchData& batchRenderData = (it->second); 251 if (batchRenderData.m_Quads.size() == 0) 252 continue; 253 254 const CVector3D vOffset(0, OVERLAY_VOFFSET, 0); 255 256 std::vector<u16> indices; 257 std::vector<QuadBatchData::SVertex> vertices; 258 259 for (size_t i = 0; i < batchRenderData.m_Quads.size(); i++) 260 { 261 const SOverlayQuad* quad = batchRenderData.m_Quads[i]; 262 263 size_t numVerticesBefore = vertices.size(); 264 vertices.push_back(QuadBatchData::SVertex(quad->m_Corners[0] + vOffset, 0, 0, quad->m_Color)); 265 vertices.push_back(QuadBatchData::SVertex(quad->m_Corners[1] + vOffset, 0, 1, quad->m_Color)); 266 vertices.push_back(QuadBatchData::SVertex(quad->m_Corners[2] + vOffset, 1, 1, quad->m_Color)); 267 vertices.push_back(QuadBatchData::SVertex(quad->m_Corners[3] + vOffset, 1, 0, quad->m_Color)); 268 269 indices.push_back(numVerticesBefore); 270 indices.push_back(numVerticesBefore + 1); 271 indices.push_back(numVerticesBefore + 2); 272 indices.push_back(numVerticesBefore); 273 indices.push_back(numVerticesBefore + 2); 274 indices.push_back(numVerticesBefore + 3); 275 } 276 277 ENSURE(batchRenderData.m_VB == NULL); 278 279 batchRenderData.m_VB = g_VBMan.Allocate(sizeof(QuadBatchData::SVertex), vertices.size(), GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER); 280 if (batchRenderData.m_VB) // allocation might fail 281 { 282 batchRenderData.m_VB->m_Owner->UpdateChunkVertices(batchRenderData.m_VB, &vertices[0]); // copy data into VBO 283 284 for (size_t k = 0; k < indices.size(); ++k) 285 indices[k] += batchRenderData.m_VB->m_Index; 286 287 batchRenderData.m_VBIndices = g_VBMan.Allocate(sizeof(u16), indices.size(), GL_DYNAMIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); 288 if (batchRenderData.m_VBIndices) 289 batchRenderData.m_VBIndices->m_Owner->UpdateChunkVertices(batchRenderData.m_VBIndices, &indices[0]); 290 } 291 } 160 292 } 161 293 162 294 void OverlayRenderer::RenderOverlaysBeforeWater() … … void OverlayRenderer::RenderOverlaysAfterWater() 196 328 { 197 329 PROFILE3_GPU("overlays (after)"); 198 330 331 RenderTexturedOverlayLines(); 332 RenderQuadOverlays(); 333 } 334 335 void OverlayRenderer::RenderTexturedOverlayLines() 336 { 199 337 #if CONFIG2_GLES 200 #warning TODO: implement OverlayRenderer::Render OverlaysAfterWaterfor GLES338 #warning TODO: implement OverlayRenderer::RenderTexturedOverlayLines for GLES 201 339 return; 202 340 #endif 341 if (m->texlines.empty()) 342 return; 203 343 204 if (!m->texlines.empty()) 205 { 206 glEnable(GL_TEXTURE_2D); 207 glEnable(GL_BLEND); 208 glDepthMask(0); 344 glEnable(GL_TEXTURE_2D); 345 glEnable(GL_BLEND); 346 glDepthMask(0); 209 347 210 211 212 213 214 348 const char* shaderName; 349 if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) 350 shaderName = "overlayline"; 351 else 352 shaderName = "fixed:overlayline"; 215 353 216 217 354 std::map<CStr, CStr> defAlwaysVisible; 355 defAlwaysVisible.insert(std::make_pair(CStr("IGNORE_LOS"), CStr("1"))); 218 356 219 357 CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); 220 358 221 222 223 359 CShaderManager& shaderManager = g_Renderer.GetShaderManager(); 360 CShaderProgramPtr shaderTexLineNormal(shaderManager.LoadProgram(shaderName)); 361 CShaderProgramPtr shaderTexLineAlwaysVisible(shaderManager.LoadProgram(shaderName, defAlwaysVisible)); 224 362 225 363 // ---------------------------------------------------------------------------------------- 226 364 227 228 229 365 shaderTexLineNormal->Bind(); 366 shaderTexLineNormal->BindTexture("losTex", los.GetTexture()); 367 shaderTexLineNormal->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); 230 368 231 232 369 // batch render only the non-always-visible overlay lines using the normal shader 370 RenderTexturedOverlayLines(shaderTexLineNormal, false); 233 371 234 372 shaderTexLineNormal->Unbind(); 235 373 236 374 // ---------------------------------------------------------------------------------------- 237 375 238 239 240 241 242 376 shaderTexLineAlwaysVisible->Bind(); 377 // TODO: losTex and losTransform are unused in the always visible shader, but I'm not sure if it's worthwhile messing 378 // with it just to remove these calls 379 shaderTexLineAlwaysVisible->BindTexture("losTex", los.GetTexture()); 380 shaderTexLineAlwaysVisible->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); 243 381 244 245 382 // batch render only the always-visible overlay lines using the LoS-ignored shader 383 RenderTexturedOverlayLines(shaderTexLineAlwaysVisible, true); 246 384 247 385 shaderTexLineAlwaysVisible->Unbind(); 248 386 249 // TODO: the shader should probably be responsible for unbinding its textures 250 g_Renderer.BindTexture(1, 0); 251 g_Renderer.BindTexture(0, 0); 387 // ---------------------------------------------------------------------------------------- 252 388 253 CVertexBuffer::Unbind(); 389 // TODO: the shader should probably be responsible for unbinding its textures 390 g_Renderer.BindTexture(1, 0); 391 g_Renderer.BindTexture(0, 0); 254 392 255 glDepthMask(1); 256 glDisable(GL_BLEND); 257 } 393 CVertexBuffer::Unbind(); 394 395 glDepthMask(1); 396 glDisable(GL_BLEND); 258 397 } 259 398 260 399 void OverlayRenderer::RenderTexturedOverlayLines(CShaderProgramPtr shaderTexLine, bool alwaysVisible) … … void OverlayRenderer::RenderTexturedOverlayLines(CShaderProgramPtr shaderTexLine 300 439 } 301 440 } 302 441 442 void OverlayRenderer::RenderQuadOverlays() 443 { 444 if (m->quadBatchData.empty()) 445 return; 446 447 glEnable(GL_TEXTURE_2D); 448 glEnable(GL_BLEND); 449 glDepthMask(0); 450 451 const char* shaderName = "overlay_selection"; 452 // TODO: create an FFP version of this shader 453 454 CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); 455 456 CShaderManager& shaderManager = g_Renderer.GetShaderManager(); 457 CShaderProgramPtr shader(shaderManager.LoadProgram(shaderName)); 458 459 shader->Bind(); 460 shader->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); 461 shader->BindTexture("losTex", los.GetTexture()); 462 463 // ---------------------------------------------------------------------------------------------------- 464 465 for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchData.begin(); it != m->quadBatchData.end(); it++) 466 { 467 QuadBatchData& batchRenderData = it->second; 468 ENSURE(batchRenderData.m_VB == NULL || batchRenderData.m_Quads.size() > 0); // if a VB was allocated, there must be at least one quad 469 470 if (!batchRenderData.m_VB) 471 continue; 472 473 const QuadBatchKey& maskPair = it->first; 474 475 shader->BindTexture("baseTex", maskPair.m_Texture->GetHandle()); 476 shader->BindTexture("maskTex", maskPair.m_TextureMask->GetHandle()); 477 478 int streamflags = shader->GetStreamFlags(); 479 480 GLsizei stride = sizeof(QuadBatchData::SVertex); 481 QuadBatchData::SVertex* vertexBase = reinterpret_cast<QuadBatchData::SVertex*>(batchRenderData.m_VB->m_Owner->Bind()); 482 483 if (streamflags & STREAM_POS) 484 shader->VertexPointer(3, GL_FLOAT, stride, &vertexBase->m_Position[0]); 485 486 if (streamflags & STREAM_UV0) 487 shader->TexCoordPointer(GL_TEXTURE0, 2, GL_SHORT, stride, &vertexBase->m_UVs[0]); 488 489 if (streamflags & STREAM_UV1) 490 shader->TexCoordPointer(GL_TEXTURE1, 2, GL_SHORT, stride, &vertexBase->m_UVs[0]); 491 492 if (streamflags & STREAM_COLOR) 493 shader->ColorPointer(4, GL_FLOAT, stride, &vertexBase->m_Color.r); 494 495 shader->AssertPointersBound(); 496 497 u8* indexBase = batchRenderData.m_VBIndices->m_Owner->Bind(); 498 glDrawElements(GL_TRIANGLES, (GLsizei) batchRenderData.m_VBIndices->m_Count, GL_UNSIGNED_SHORT, indexBase + sizeof(u16) * batchRenderData.m_VBIndices->m_Index); 499 500 g_Renderer.GetStats().m_OverlayTris += batchRenderData.m_VB->m_Count/2; 501 } 502 503 // ---------------------------------------------------------------------------------------------------- 504 505 shader->Unbind(); 506 507 // TODO: the shader should probably be responsible for unbinding its textures 508 g_Renderer.BindTexture(1, 0); 509 g_Renderer.BindTexture(0, 0); 510 511 CVertexBuffer::Unbind(); 512 513 glDepthMask(1); 514 glDisable(GL_BLEND); 515 } 516 303 517 void OverlayRenderer::RenderForegroundOverlays(const CCamera& viewCamera) 304 518 { 305 519 PROFILE3_GPU("overlays (fg)"); … … void CTexturedLineRData::Update() 361 575 m_VBIndices = NULL; 362 576 } 363 577 364 CTerrain* terrain = m_Line->m_Terrain; 365 CmpPtr<ICmpWaterManager> cmpWaterManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY); 578 if (!m_Line->m_SimContext) 579 { 580 debug_warn(L"[OverlayRenderer] No SimContext set for textured overlay line, cannot render (no terrain data)"); 581 return; 582 } 583 584 const CTerrain& terrain = m_Line->m_SimContext->GetTerrain(); 585 CmpPtr<ICmpWaterManager> cmpWaterManager(*m_Line->m_SimContext, SYSTEM_ENTITY); 366 586 367 587 float v = 0.f; 368 588 std::vector<SVertex> vertices; … … void CTexturedLineRData::Update() 398 618 // TODO: if we ever support more than one water level per map, recompute this per point 399 619 float w = cmpWaterManager->GetExactWaterLevel(p0.X, p0.Z); 400 620 401 p0.Y = terrain ->GetExactGroundLevel(p0.X, p0.Z);621 p0.Y = terrain.GetExactGroundLevel(p0.X, p0.Z); 402 622 if (p0.Y < w) 403 623 p0.Y = w; 404 624 405 p1.Y = terrain ->GetExactGroundLevel(p1.X, p1.Z);625 p1.Y = terrain.GetExactGroundLevel(p1.X, p1.Z); 406 626 if (p1.Y < w) 407 627 { 408 628 p1.Y = w; 409 629 p1floating = true; 410 630 } 411 631 412 p2.Y = terrain ->GetExactGroundLevel(p2.X, p2.Z);632 p2.Y = terrain.GetExactGroundLevel(p2.X, p2.Z); 413 633 if (p2.Y < w) 414 634 { 415 635 p2.Y = w; … … void CTexturedLineRData::Update() 426 646 if (p1floating) 427 647 norm = CVector3D(0, 1, 0); 428 648 else 429 norm = m_Line->m_Terrain->CalcExactNormal(p1.X, p1.Z);649 norm = terrain.CalcExactNormal(p1.X, p1.Z); 430 650 431 651 CVector3D b = ((p1 - p0).Normalized() + (p2 - p1).Normalized()).Cross(norm); 432 652 … … void CTexturedLineRData::Update() 445 665 // What the code below does is push the indices for a quad composed of two triangles in each iteration. The two triangles 446 666 // of each quad are indexed using the winding orders (BR, BL, TR) and (TR, BL, TR) (where BR is bottom-right of this 447 667 // iteration's quad, TR top-right etc). 448 SVertex vertex1(p1 + b + norm* m_Raise, 0.f, v);449 SVertex vertex2(p1 - b + norm* m_Raise, 1.f, v);668 SVertex vertex1(p1 + b + norm*OverlayRenderer::OVERLAY_VOFFSET, 0.f, v); 669 SVertex vertex2(p1 - b + norm*OverlayRenderer::OVERLAY_VOFFSET, 1.f, v); 450 670 vertices.push_back(vertex1); 451 671 vertices.push_back(vertex2); 452 672 … … void CTexturedLineRData::Update() 495 715 else 496 716 p2 = CVector3D(m_Line->m_Coords[((i+2) % n)*2], 0, m_Line->m_Coords[((i+2) % n)*2+1]); 497 717 498 p2.Y = terrain ->GetExactGroundLevel(p2.X, p2.Z);718 p2.Y = terrain.GetExactGroundLevel(p2.X, p2.Z); 499 719 if (p2.Y < w) 500 720 { 501 721 p2.Y = w; … … void CTexturedLineRData::Update() 538 758 539 759 for (unsigned i = 0; i < capIndices.size(); i++) 540 760 capIndices[i] += vertices.size(); 761 541 762 vertices.insert(vertices.end(), capVertices.begin(), capVertices.end()); 542 763 indices.insert(indices.end(), capIndices.begin(), capIndices.end()); 543 764 … … void CTexturedLineRData::Update() 558 779 559 780 for (unsigned i = 0; i < capIndices.size(); i++) 560 781 capIndices[i] += vertices.size(); 782 561 783 vertices.insert(vertices.end(), capVertices.begin(), capVertices.end()); 562 784 indices.insert(indices.end(), capIndices.begin(), capIndices.end()); 563 785 } … … void CTexturedLineRData::CreateLineCap(const CVector3D& corner1, const CVector3D 698 920 } 699 921 700 922 } 923 924 size_t QuadBatchKey::hash::operator()(const QuadBatchKey& d) const 925 { 926 size_t seed = 0; 927 boost::hash_combine(seed, d.m_Texture); 928 boost::hash_combine(seed, d.m_TextureMask); 929 return seed; 930 } 931 932 bool QuadBatchKey::eq::operator()(const QuadBatchKey& d1, const QuadBatchKey& d2) const 933 { 934 return (d1.m_Texture == d2.m_Texture 935 && d1.m_TextureMask == d2.m_TextureMask); 936 } 937 No newline at end of file -
source/renderer/OverlayRenderer.h
diff --git a/source/renderer/OverlayRenderer.h b/source/renderer/OverlayRenderer.h index 6c1dfdc..4e8eb7e 100644
a b 23 23 struct SOverlayLine; 24 24 struct SOverlayTexturedLine; 25 25 struct SOverlaySprite; 26 struct SOverlayQuad; 26 27 class CCamera; 27 28 28 29 struct OverlayRendererInternals; … … public: 39 40 40 41 /** 41 42 * Add a line overlay for rendering in this frame. 43 * @param overlay Must be non-null. 42 44 */ 43 45 void Submit(SOverlayLine* overlay); 44 46 45 47 /** 46 48 * Add a textured line overlay for rendering in this frame. 49 * @param overlay Must be non-null. 47 50 */ 48 51 void Submit(SOverlayTexturedLine* overlay); 49 52 50 53 /** 51 54 * Add a sprite overlay for rendering in this frame. 55 * @param overlay Must be non-null. 52 56 */ 53 57 void Submit(SOverlaySprite* overlay); 54 58 55 59 /** 60 * Add a textured quad overlay for rendering in this frame. 61 * @param overlay Must be non-null. 62 */ 63 void Submit(SOverlayQuad* overlay); 64 65 /** 66 * Add a selection ring overlay for rendering in this frame. 67 */ 68 //void Submit(SOverlaySelectionOutline* selectionRing); 69 70 /** 56 71 * Prepare internal data structures for rendering. 57 72 * Must be called after all Submit calls for a frame, and before 58 73 * any rendering calls. … … public: 85 100 */ 86 101 void RenderForegroundOverlays(const CCamera& viewCamera); 87 102 103 /// Small vertical offset of overlays from terrain to prevent visual glitches 104 static const float OVERLAY_VOFFSET; 105 88 106 private: 89 107 90 108 /** 109 * Helper method; renders all overlay lines currently registered in the internals. Batch renders textured overlay lines 110 * according to their visibility status by delegating to RenderTexturedOverlayLines(CShaderProgramPtr, bool). 111 */ 112 void RenderTexturedOverlayLines(); 113 114 /** 91 115 * Helper method; renders those overlay lines currently registered in the internals (i.e. in m->texlines) for which the 92 116 * always visible flag equals @alwaysVisible. Used for batch rendering the overlay lines by their alwaysVisible status, 93 117 * because this requires a separate shader to be used. 94 118 */ 95 119 void RenderTexturedOverlayLines(CShaderProgramPtr shader, bool alwaysVisible); 96 120 121 /** 122 * Helper method; batch-renders all registered quad overlays according to their texture. 123 */ 124 void RenderQuadOverlays(); 125 97 126 private: 98 127 OverlayRendererInternals* m; 99 128 }; -
source/renderer/Renderer.cpp
diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index 7dfce3c..13f7aeb 100644
a b void CRenderer::Submit(SOverlaySprite* overlay) 1729 1729 m->overlayRenderer.Submit(overlay); 1730 1730 } 1731 1731 1732 void CRenderer::Submit(SOverlayQuad* overlay) 1733 { 1734 m->overlayRenderer.Submit(overlay); 1735 } 1736 1737 /*void CRenderer::Submit(SOverlaySelectionOutline* overlay) 1738 { 1739 m->overlayRenderer.Submit(overlay); 1740 }*/ 1741 1732 1742 void CRenderer::Submit(CModelDecal* decal) 1733 1743 { 1734 1744 m->terrainRenderer->Submit(decal); -
source/renderer/Renderer.h
diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index 74e6d46..239efe1 100644
a b protected: 325 325 void Submit(SOverlayLine* overlay); 326 326 void Submit(SOverlayTexturedLine* overlay); 327 327 void Submit(SOverlaySprite* overlay); 328 void Submit(SOverlayQuad* overlay); 328 329 void Submit(CModelDecal* decal); 329 330 void Submit(CParticleEmitter* emitter); 330 331 void SubmitNonRecursive(CModel* model); -
source/renderer/Scene.h
diff --git a/source/renderer/Scene.h b/source/renderer/Scene.h index 2018135..99c99f7 100644
a b class CTerritoryTexture; 39 39 struct SOverlayLine; 40 40 struct SOverlayTexturedLine; 41 41 struct SOverlaySprite; 42 struct SOverlayQuad; 42 43 43 44 class SceneCollector; 44 45 … … public: 104 105 virtual void Submit(SOverlaySprite* overlay) = 0; 105 106 106 107 /** 108 * Submit a textured quad overlay. 109 */ 110 virtual void Submit(SOverlayQuad* overlay) = 0; 111 112 /** 107 113 * Submit a terrain decal. 108 114 */ 109 115 virtual void Submit(CModelDecal* decal) = 0; -
source/renderer/VertexBuffer.cpp
diff --git a/source/renderer/VertexBuffer.cpp b/source/renderer/VertexBuffer.cpp index bcbfebe..84fce45 100644
a b CVertexBuffer::CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target) 33 33 { 34 34 size_t size = MAX_VB_SIZE_BYTES; 35 35 36 if (target == GL_ARRAY_BUFFER) 36 if (target == GL_ARRAY_BUFFER) // vertex data buffer 37 37 { 38 38 // We want to store 16-bit indices to any vertex in a buffer, so the 39 // buffer must never be bigger than vertexSize*64K bytes 39 // buffer must never be bigger than vertexSize*64K bytes since we can 40 // address at most 64K of them with 16-bit indices 40 41 size = std::min(size, vertexSize*65536); 41 42 } 42 43 … … CVertexBuffer::CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target) 54 55 } 55 56 56 57 // store max/free vertex counts 57 m_MaxVertices =m_FreeVertices=size/vertexSize;58 m_MaxVertices = m_FreeVertices = size/vertexSize; 58 59 59 60 // create sole free chunk 60 VBChunk* chunk =new VBChunk;61 chunk->m_Owner =this;62 chunk->m_Count =m_FreeVertices;63 chunk->m_Index =0;61 VBChunk* chunk = new VBChunk; 62 chunk->m_Owner = this; 63 chunk->m_Count = m_FreeVertices; 64 chunk->m_Index = 0; 64 65 m_FreeList.push_front(chunk); 65 66 } 66 67 … … CVertexBuffer::VBChunk* CVertexBuffer::Allocate(size_t vertexSize, size_t numVer 100 101 return 0; 101 102 102 103 // trawl free list looking for first free chunk with enough space 103 VBChunk* chunk =0;104 VBChunk* chunk = 0; 104 105 typedef std::list<VBChunk*>::iterator Iter; 105 for (Iter iter =m_FreeList.begin();iter!=m_FreeList.end();++iter) {106 if (numVertices <=(*iter)->m_Count) {107 chunk =*iter;106 for (Iter iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter) { 107 if (numVertices <= (*iter)->m_Count) { 108 chunk = *iter; 108 109 // remove this chunk from the free list 109 110 m_FreeList.erase(iter); 110 111 m_FreeVertices -= chunk->m_Count; … … void CVertexBuffer::Release(VBChunk* chunk) 173 174 174 175 /////////////////////////////////////////////////////////////////////////////// 175 176 // UpdateChunkVertices: update vertex data for given chunk 176 void CVertexBuffer::UpdateChunkVertices(VBChunk* chunk, void* data)177 void CVertexBuffer::UpdateChunkVertices(VBChunk* chunk, void* data, unsigned int cnt /* = 0*/) 177 178 { 178 179 if (g_Renderer.m_Caps.m_VBO) 179 180 { -
source/renderer/VertexBuffer.h
diff --git a/source/renderer/VertexBuffer.h b/source/renderer/VertexBuffer.h index 809ac65..a4579e2 100644
a b 30 30 // absolute maximum (bytewise) size of each GL vertex buffer object 31 31 #define MAX_VB_SIZE_BYTES (512*1024) 32 32 33 /////////////////////////////////////////////////////////////////////////////// 34 // CVertexBuffer: encapsulation of ARB_vertex_buffer_object, also supplying 35 // some additional functionality for sharing buffers between multiple objects 33 /** 34 * CVertexBuffer: encapsulation of ARB_vertex_buffer_object, also supplying 35 * some additional functionality for sharing buffers between multiple objects 36 */ 36 37 class CVertexBuffer 37 38 { 38 39 public: 39 // VBChunk: describes a portion of this vertex buffer 40 41 /// VBChunk: describes a portion of this vertex buffer 40 42 struct VBChunk 41 43 { 42 // owningbuffer44 /// Owning (parent) vertex buffer 43 45 CVertexBuffer* m_Owner; 44 // start index of this chunk in owner46 /// Start index of this chunk in owner 45 47 size_t m_Index; 46 // number of vertices used by chunk48 /// Number of vertices used by chunk 47 49 size_t m_Count; 48 50 49 51 private: … … public: 59 61 CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target); 60 62 ~CVertexBuffer(); 61 63 62 // bind to this buffer; return pointer to address required as parameter63 // to glVertexPointer ( + etc) calls64 /// Bind to this buffer; return pointer to address required as parameter 65 /// to glVertexPointer ( + etc) calls 64 66 u8* Bind(); 65 67 66 // get the address that Bind() will return, without actually binding68 /// Get the address that Bind() will return, without actually binding 67 69 u8* GetBindAddress(); 68 70 69 // unbind any currently-bound buffer, so glVertexPointer etc calls will not attempt to use it71 /// Unbind any currently-bound buffer, so glVertexPointer etc calls will not attempt to use it 70 72 static void Unbind(); 71 73 72 // update vertex data for given chunk73 void UpdateChunkVertices(VBChunk* chunk, void* data );74 /// Update vertex data for given chunk. Transfers the provided data to the actual OpenGL vertex buffer. 75 void UpdateChunkVertices(VBChunk* chunk, void* data, unsigned int cnt = 0); 74 76 75 77 size_t GetVertexSize() const { return m_VertexSize; } 76 77 78 size_t GetBytesReserved() const; 78 79 size_t GetBytesAllocated() const; 79 80 81 /// Returns true if this vertex buffer is compatible with the specified vertex type and intended usage. 80 82 bool CompatibleVertexType(size_t vertexSize, GLenum usage, GLenum target); 81 83 82 84 void DumpStatus(); … … public: 84 86 protected: 85 87 friend class CVertexBufferManager; // allow allocate only via CVertexBufferManager 86 88 87 // try to allocate a buffer of given number of vertices (each of given size),88 // and with the given type - return null if no free chunks available89 /// Try to allocate a buffer of given number of vertices (each of given size), 90 /// and with the given type - return null if no free chunks available 89 91 VBChunk* Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target); 90 // return given chunk to this buffer92 /// Return given chunk to this buffer 91 93 void Release(VBChunk* chunk); 92 94 93 95 94 96 private: 95 // vertex size of this vertex buffer97 /// Vertex size of this vertex buffer 96 98 size_t m_VertexSize; 97 // number of vertices of above size in this buffer99 /// Number of vertices of above size in this buffer 98 100 size_t m_MaxVertices; 99 // list of free chunks in this buffer101 /// List of free chunks in this buffer 100 102 std::list<VBChunk*> m_FreeList; 101 // available free vertices - total of all free vertices in the free list103 /// Available free vertices - total of all free vertices in the free list 102 104 size_t m_FreeVertices; 103 // handle to the actual GL vertex buffer object105 /// Handle to the actual GL vertex buffer object 104 106 GLuint m_Handle; 105 // raw system memory for systems not supporting VBOs107 /// Raw system memory for systems not supporting VBOs 106 108 u8* m_SysMem; 107 // usage type of the buffer (GL_STATIC_DRAW etc)109 /// Usage type of the buffer (GL_STATIC_DRAW etc) 108 110 GLenum m_Usage; 109 // buffer target (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER)111 /// Buffer target (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER) 110 112 GLenum m_Target; 111 113 }; 112 114 -
source/renderer/VertexBufferManager.h
diff --git a/source/renderer/VertexBufferManager.h b/source/renderer/VertexBufferManager.h index b97c68d..568e96a 100644
a b 30 30 class CVertexBufferManager 31 31 { 32 32 public: 33 // Explicit shutdown of the vertex buffer subsystem34 void Shutdown();35 33 36 34 /** 37 35 * Try to allocate a vertex buffer of the given size and type. … … public: 44 42 */ 45 43 CVertexBuffer::VBChunk* Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target); 46 44 47 // return given chunk to its owner45 /// Returns the given @p chunk to its owning buffer 48 46 void Release(CVertexBuffer::VBChunk* chunk); 49 47 50 // returnlist of all buffers48 /// Returns a list of all buffers 51 49 const std::list<CVertexBuffer*>& GetBufferList() const { return m_Buffers; } 52 50 53 51 size_t GetBytesReserved(); 54 52 size_t GetBytesAllocated(); 55 53 54 /// Returns the maximum possible size of a single vertex buffer 55 size_t GetMaxBufferSize() const { return MAX_VB_SIZE_BYTES; } 56 57 /// Explicit shutdown of the vertex buffer subsystem; releases all currently-allocated buffers. 58 void Shutdown(); 59 56 60 private: 57 // list of all known vertex buffers61 /// List of all known vertex buffers 58 62 std::list<CVertexBuffer*> m_Buffers; 59 63 }; 60 64 -
source/simulation2/components/CCmpRallyPointRenderer.cpp
diff --git a/source/simulation2/components/CCmpRallyPointRenderer.cpp b/source/simulation2/components/CCmpRallyPointRenderer.cpp index 78d9730..06d18e3 100644
a b void CCmpRallyPointRenderer::ConstructOverlayLines() 600 600 // construct solid textured overlay line along a subset of the full path points from startPointIdx to endPointIdx 601 601 SOverlayTexturedLine overlayLine; 602 602 overlayLine.m_Thickness = m_LineThickness; 603 overlayLine.m_ Terrain = cmpTerrain->GetCTerrain();603 overlayLine.m_SimContext = &GetSimContext(); 604 604 overlayLine.m_TextureBase = m_Texture; 605 605 overlayLine.m_TextureMask = m_TextureMask; 606 606 overlayLine.m_Color = m_LineColor; … … void CCmpRallyPointRenderer::ConstructOverlayLines() 624 624 } 625 625 else 626 626 { 627 // construct dashed line from startPointIdx to endPointIdx ,add textured overlay lines for it to the render list627 // construct dashed line from startPointIdx to endPointIdx; add textured overlay lines for it to the render list 628 628 std::vector<CVector2D> straightLine; 629 629 straightLine.push_back(m_Path[segment.m_StartIndex]); 630 630 straightLine.push_back(m_Path[segment.m_EndIndex]); 631 631 632 // We always want to have the dashed lineend at either point with a full dash (i.e. not a cleared space), so that the dashed633 // area is visually obvious. Th at implies that we want at least So, let's do some calculations to see what size we should make634 // t he dashes and clears.632 // We always want to the dashed line to end at either point with a full dash (i.e. not a cleared space), so that the dashed 633 // area is visually obvious. This requires some calculations to see what size we should make the dashes and clears for them 634 // to fit exactly. 635 635 636 636 float maxDashSize = 3.f; 637 637 float maxClearSize = 3.f; … … void CCmpRallyPointRenderer::ConstructOverlayLines() 642 642 643 643 float distance = (m_Path[segment.m_StartIndex] - m_Path[segment.m_EndIndex]).Length(); // straight-line distance between the points 644 644 645 // see how many pairs (dash + clear) can fit into the distance unmodified. Then check the remaining distance; if it's not exactly646 // a dash size's worth ( and it likely won't be), then adjust the dash/clear sizes slightly so that it is.645 // See how many pairs (dash + clear) of unmodified size can fit into the distance. Then check the remaining distance; if it's not exactly 646 // a dash size's worth (which it probably won't be), then adjust the dash/clear sizes slightly so that it is. 647 647 int numFitUnmodified = floor(distance/(dashSize + clearSize)); 648 648 float remainderDistance = distance - (numFitUnmodified * (dashSize + clearSize)); 649 649 … … void CCmpRallyPointRenderer::ConstructOverlayLines() 672 672 SOverlayTexturedLine dashOverlay; 673 673 674 674 dashOverlay.m_Thickness = m_LineThickness; 675 dashOverlay.m_ Terrain = cmpTerrain->GetCTerrain();675 dashOverlay.m_SimContext = &GetSimContext(); 676 676 dashOverlay.m_TextureBase = m_Texture; 677 677 dashOverlay.m_TextureMask = m_TextureMask; 678 678 dashOverlay.m_Color = m_LineDashColor; … … void CCmpRallyPointRenderer::FixFootprintWaypoints(std::vector<CVector2D>& coord 757 757 { 758 758 case ICmpFootprint::SQUARE: 759 759 { 760 // in this case, footprintSize0 and 1 respectively indicate the (unrotated) size along the X and Z axes760 // in this case, footprintSize0 and 1 indicate the size along the X and Z axes, respectively. 761 761 762 762 // the building's footprint could be rotated any which way, so let's get the rotation around the Y axis 763 763 // and the rotated unit vectors in the X/Z plane of the shape's footprint … … void CCmpRallyPointRenderer::FixInvisibleWaypoints(std::vector<CVector2D>& coord 827 827 player_id_t currentPlayer = GetSimContext().GetCurrentDisplayedPlayer(); 828 828 CLosQuerier losQuerier(cmpRangeMgr->GetLosQuerier(currentPlayer)); 829 829 830 //for (std::vector<Waypoint>::iterator it = waypoints.begin(); it != waypoints.end();)831 830 for(std::vector<CVector2D>::iterator it = coords.begin(); it != coords.end();) 832 831 { 833 832 int i = (fixed::FromFloat(it->X) / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNearest(); -
source/simulation2/components/CCmpSelectable.cpp
diff --git a/source/simulation2/components/CCmpSelectable.cpp b/source/simulation2/components/CCmpSelectable.cpp index d23916f..c3593da 100644
a b 20 20 #include "simulation2/system/Component.h" 21 21 #include "ICmpSelectable.h" 22 22 23 #include "ICmpPosition.h"24 #include "ICmpFootprint.h"25 #include "ICmpVisual.h"26 #include "simulation2/MessageTypes.h"27 #include "simulation2/helpers/Render.h"28 29 23 #include "graphics/Overlay.h" 24 #include "graphics/Terrain.h" 25 #include "graphics/TextureManager.h" 30 26 #include "maths/MathUtil.h" 31 27 #include "maths/Matrix3D.h" 32 28 #include "maths/Vector3D.h" 29 #include "maths/Vector2D.h" 30 #include "ps/CLogger.h" 33 31 #include "renderer/Scene.h" 32 #include "renderer/Renderer.h" 33 #include "simulation2/MessageTypes.h" 34 #include "simulation2/components/ICmpPosition.h" 35 #include "simulation2/components/ICmpFootprint.h" 36 #include "simulation2/components/ICmpVisual.h" 37 #include "simulation2/components/ICmpTerrain.h" 38 #include "simulation2/components/ICmpOwnership.h" 39 #include "simulation2/components/ICmpPlayer.h" 40 #include "simulation2/components/ICmpPlayerManager.h" 41 #include "simulation2/components/ICmpWaterManager.h" 42 #include "simulation2/helpers/Render.h" 34 43 35 44 class CCmpSelectable : public ICmpSelectable 36 45 { … … public: 39 48 { 40 49 componentManager.SubscribeToMessageType(MT_Interpolate); 41 50 componentManager.SubscribeToMessageType(MT_RenderSubmit); 51 // these next two are primarily for invalidating the static building outlines; not really applicable for unit 52 // overlays since their positions and ownerships etc. are gathered every frame 53 componentManager.SubscribeToMessageType(MT_OwnershipChanged); 54 componentManager.SubscribeToMessageType(MT_PositionChanged); 42 55 // TODO: it'd be nice if we didn't get these messages except in the rare 43 56 // cases where we're actually drawing a selection highlight 44 57 } 45 58 46 59 DEFAULT_COMPONENT_ALLOCATOR(Selectable) 47 60 48 SOverlayLine m_Overlay;49 SOverlayLine* m_DebugBoundingBoxOverlay;50 SOverlayLine* m_DebugSelectionBoxOverlay;51 bool m_EditorOnly;52 53 61 CCmpSelectable() 54 : m_DebugBoundingBoxOverlay(NULL), m_DebugSelectionBoxOverlay(NULL) 62 : m_DebugBoundingBoxOverlay(NULL), m_DebugSelectionBoxOverlay(NULL), 63 m_AlphaTarget(0.f), m_BuildingOverlay(NULL), m_UnitOverlay(NULL) 55 64 { 56 m_Overlay.m_Thickness = 2; 57 m_Overlay.m_Color = CColor(0, 0, 0, 0); 65 m_Color = CColor(0, 0, 0, m_AlphaTarget); 58 66 } 59 67 60 ~CCmpSelectable(){ 68 ~CCmpSelectable() 69 { 61 70 delete m_DebugBoundingBoxOverlay; 62 71 delete m_DebugSelectionBoxOverlay; 72 delete m_BuildingOverlay; 73 delete m_UnitOverlay; 63 74 } 64 75 65 76 static std::string GetSchema() … … public: 71 82 "<element name='EditorOnly' a:help='If this element is present, the entity is only selectable in Atlas'>" 72 83 "<empty/>" 73 84 "</element>" 74 "</optional>"; 85 "</optional>" 86 "<element name='Overlay' a:help='Specifies the type of overlay to be displayed when this entity is selected'>" 87 "<choice>" 88 "<element name='Texture' a:help='Displays a texture underneath the entity'>" 89 "<element name='MainTexture'><text/></element>" 90 "<element name='MainTextureMask'><text/></element>" 91 "</element>" 92 "<element name='Outline' a:help='Traces the outline of the entity with a line texture'>" 93 "<element name='LineTexture'><text/></element>" 94 "<element name='LineTextureMask'><text/></element>" 95 "<element name='LineThickness'><ref name='positiveDecimal'/></element>" 96 "</element>" 97 "</choice>" 98 "</element>"; 75 99 } 76 100 77 101 virtual void Init(const CParamNode& paramNode) 78 102 { 79 103 m_EditorOnly = paramNode.GetChild("EditorOnly").IsOk(); 80 }81 104 82 virtual void Deinit() 83 { 105 const CParamNode& textureNode = paramNode.GetChild("Overlay").GetChild("Texture"); 106 const CParamNode& outlineNode = paramNode.GetChild("Overlay").GetChild("Outline"); 107 108 // TODO: we might be able to save some memory by de-duplicating these descriptors (particularly if actors 109 // also end up having Selectable components -- see CCmpTemplateManager::ConstructTemplateActor) 110 111 if (textureNode.IsOk()) 112 { 113 // textured quad mode 114 m_OverlayDescriptor.m_Type = ICmpSelectable::DYNAMIC_QUAD; 115 m_OverlayDescriptor.m_QuadTexture = textureNode.GetChild("MainTexture").ToString(); 116 m_OverlayDescriptor.m_QuadTextureMask = textureNode.GetChild("MainTextureMask").ToString(); 117 } 118 else if (outlineNode.IsOk()) 119 { 120 // outline mode 121 m_OverlayDescriptor.m_Type = ICmpSelectable::STATIC_OUTLINE; 122 m_OverlayDescriptor.m_LineTexture = outlineNode.GetChild("LineTexture").ToString(); 123 m_OverlayDescriptor.m_LineTextureMask = outlineNode.GetChild("LineTextureMask").ToString(); 124 m_OverlayDescriptor.m_LineThickness = outlineNode.GetChild("LineThickness").ToFixed().ToFloat(); 125 } 84 126 } 85 127 128 virtual void Deinit() { } 129 86 130 virtual void Serialize(ISerializer& UNUSED(serialize)) 87 131 { 88 132 // Nothing to do here (the overlay object is not worth saving, it'll get … … public: 95 139 Init(paramNode); 96 140 } 97 141 98 virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) 142 virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)); 143 144 virtual void SetSelectionHighlight(CColor color) 99 145 { 100 switch (msg.GetType()) 101 { 102 case MT_Interpolate: 146 m_Color.r = color.r; 147 m_Color.g = color.g; 148 m_Color.b = color.b; 149 m_AlphaTarget = color.a; // set target for alpha fading 150 } 151 152 virtual bool IsEditorOnly() 153 { 154 return m_EditorOnly; 155 } 156 157 void RenderSubmit(SceneCollector& collector); 158 159 void UpdateStaticOverlay(); 160 void UpdateDynamicOverlay(float frameOffset); 161 162 void InvalidateStaticOverlay(); 163 164 private: 165 SOverlayDescriptor m_OverlayDescriptor; 166 SOverlayTexturedLine* m_BuildingOverlay; 167 SOverlayQuad* m_UnitOverlay; 168 169 SOverlayLine* m_DebugBoundingBoxOverlay; 170 SOverlayLine* m_DebugSelectionBoxOverlay; 171 172 bool m_EditorOnly; 173 CColor m_Color; ///< Current selection overlay color (including alpha component for fading) 174 float m_AlphaTarget; // fade target 175 }; 176 177 void CCmpSelectable::HandleMessage(const CMessage& msg, bool UNUSED(global)) 178 { 179 switch (msg.GetType()) 180 { 181 case MT_Interpolate: 103 182 { 104 if (m_Overlay.m_Color.a > 0) 183 // update dynamic overlay only when visible 184 if (m_Color.a > 0) 105 185 { 106 float offset = static_cast<const CMessageInterpolate&> (msg).offset;107 ConstructShape(offset);186 const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg); 187 UpdateDynamicOverlay(msgData.offset); 108 188 } 109 189 break; 110 190 } 111 case MT_RenderSubmit:191 case MT_OwnershipChanged: 112 192 { 113 if (m_Overlay.m_Color.a > 0) 193 const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); 194 195 // don't update color if there's no new owner (e.g. the unit died) 196 if (msgData.to == INVALID_PLAYER) 197 break; 198 199 // update the selection highlight color 200 // TODO: very similar to CCmpMinimap's MT_OwnershipChanged handler, consider factoring this out 201 CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSimContext(), SYSTEM_ENTITY); 202 if (!cmpPlayerManager) 203 break; 204 205 CmpPtr<ICmpPlayer> cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(msgData.to)); 206 if (!cmpPlayer) 207 break; 208 209 CColor color = cmpPlayer->GetColour(); 210 SetSelectionHighlight(CColor(color.r, color.g, color.b, m_AlphaTarget)); // keep current alpha target, change only RGB 211 } 212 // fall-through 213 case MT_PositionChanged: 214 { 215 InvalidateStaticOverlay(); 216 break; 217 } 218 case MT_RenderSubmit: 219 { 220 // fade overlay alpha to target alpha 221 const float fadeSpeed = 0.3f; // ]0,1[, higher = faster 222 223 if (m_Color.a != m_AlphaTarget) // should be cheap enough to perform every frame for every selectable while also quickly eliminating many hidden overlays 114 224 { 115 const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg); 116 RenderSubmit(msgData.collector); 225 float targetDiff = m_AlphaTarget - m_Color.a; 226 if (fabs(targetDiff) > 0.001f) 227 { 228 m_Color.a += targetDiff * fadeSpeed; // apply a fraction of the remainder distance each frame 229 } 230 else 231 { 232 // snap to the target value so we don't keep rendering because the alpha is like 0.000005 or sth when the 233 // target alpha is set to 0 to hide the overlay 234 m_Color.a = m_AlphaTarget; 235 } 117 236 } 237 238 const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg); 239 RenderSubmit(msgData.collector); 240 118 241 break; 119 242 } 120 }121 243 } 244 } 122 245 123 virtual bool IsEditorOnly() 246 void CCmpSelectable::InvalidateStaticOverlay() 247 { 248 SAFE_DELETE(m_BuildingOverlay); 249 } 250 251 void CCmpSelectable::UpdateStaticOverlay() 252 { 253 if (m_BuildingOverlay || m_OverlayDescriptor.m_Type != STATIC_OUTLINE) 254 return; 255 256 entity_id_t entityId = GetEntityId(); 257 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), entityId); 258 CmpPtr<ICmpFootprint> cmpFootprint(GetSimContext(), entityId); 259 CmpPtr<ICmpOwnership> cmpOwnership(GetSimContext(), entityId); 260 if (!cmpFootprint || !cmpPosition) 261 return; 262 263 CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY); 264 CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSimContext(), SYSTEM_ENTITY); 265 if (!cmpTerrain) 266 return; // should never happen 267 268 // grab position/footprint data 269 CFixedVector2D position = cmpPosition->GetPosition2D(); 270 CFixedVector3D rotation = cmpPosition->GetRotation(); 271 272 ICmpFootprint::EShape fpShape; 273 entity_pos_t fpSize0_fixed, fpSize1_fixed, fpHeight_fixed; 274 cmpFootprint->GetShape(fpShape, fpSize0_fixed, fpSize1_fixed, fpHeight_fixed); 275 276 CTextureProperties texturePropsBase(m_OverlayDescriptor.m_LineTexture); 277 texturePropsBase.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); 278 texturePropsBase.SetMaxAnisotropy(4.f); 279 280 CTextureProperties texturePropsMask(m_OverlayDescriptor.m_LineTextureMask); 281 texturePropsMask.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); 282 texturePropsMask.SetMaxAnisotropy(4.f); 283 284 // ------------------------------------------------------------------------------------- 285 286 m_BuildingOverlay = new SOverlayTexturedLine; 287 m_BuildingOverlay->m_AlwaysVisible = false; 288 m_BuildingOverlay->m_Closed = true; 289 m_BuildingOverlay->m_SimContext = &GetSimContext(); 290 m_BuildingOverlay->m_Thickness = m_OverlayDescriptor.m_LineThickness; 291 292 if (g_Renderer.IsInitialised()) 124 293 { 125 return m_EditorOnly; 294 m_BuildingOverlay->m_TextureBase = g_Renderer.GetTextureManager().CreateTexture(texturePropsBase); 295 m_BuildingOverlay->m_TextureMask = g_Renderer.GetTextureManager().CreateTexture(texturePropsMask); 126 296 } 127 128 virtual void SetSelectionHighlight(CColor color) 297 else 129 298 { 130 m_Overlay.m_Color = color; 299 LOGWARNING(L"[CCmpSelectable] Cannot update static selection overlay; renderer not initialized"); 300 } 301 302 CVector2D origin(position.X.ToFloat(), position.Y.ToFloat()); 131 303 132 if (color.a == 0 && !m_Overlay.m_Coords.empty()) 304 switch (fpShape) 305 { 306 case ICmpFootprint::SQUARE: 133 307 { 134 // Delete the overlay data to save memory (we don't want hundreds of bytes 135 // times thousands of units when the selections are not being rendered any more) 136 std::vector<float> empty; 137 m_Overlay.m_Coords.swap(empty); 138 ENSURE(m_Overlay.m_Coords.capacity() == 0); 308 float s = sinf(-rotation.Y.ToFloat()); 309 float c = cosf(-rotation.Y.ToFloat()); 310 CVector2D unitX(c, s); 311 CVector2D unitZ(-s, c); 312 313 // add half the line thickness to the radius so that we get an 'outside' stroke of the footprint shape 314 const float halfSizeX = fpSize0_fixed.ToFloat()/2.f + m_BuildingOverlay->m_Thickness/2.f; 315 const float halfSizeZ = fpSize1_fixed.ToFloat()/2.f + m_BuildingOverlay->m_Thickness/2.f; 316 317 std::vector<CVector2D> points; 318 points.push_back(CVector2D(origin + unitX * halfSizeX + unitZ *(-halfSizeZ))); 319 points.push_back(CVector2D(origin + unitX *(-halfSizeX) + unitZ *(-halfSizeZ))); 320 points.push_back(CVector2D(origin + unitX *(-halfSizeX) + unitZ * halfSizeZ)); 321 points.push_back(CVector2D(origin + unitX * halfSizeX + unitZ * halfSizeZ)); 322 323 SimRender::SubdividePoints(points, TERRAIN_TILE_SIZE/3.f, m_BuildingOverlay->m_Closed); 324 m_BuildingOverlay->PushCoords(points); 139 325 } 326 break; 327 case ICmpFootprint::CIRCLE: 328 { 329 const float radius = fpSize0_fixed.ToFloat() + m_BuildingOverlay->m_Thickness/3.f; 330 if (radius > 0) // prevent catastrophic failure 331 { 332 float stepAngle; 333 unsigned numSteps; 334 SimRender::AngularStepFromChordLen(TERRAIN_TILE_SIZE/3.f, radius, stepAngle, numSteps); 140 335 141 // TODO: it'd be nice to fade smoothly (but quickly) from transparent to solid 336 for (unsigned i = 0; i < numSteps; i++) // '<' is sufficient because the line is closed automatically 337 { 338 float angle = i * stepAngle; 339 float px = origin.X + radius * sinf(angle); 340 float pz = origin.Y + radius * cosf(angle); 341 342 m_BuildingOverlay->PushCoords(px, pz); 343 } 344 } 345 } 346 break; 142 347 } 143 348 144 void ConstructShape(float frameOffset) 349 ENSURE(m_BuildingOverlay); 350 } 351 352 void CCmpSelectable::UpdateDynamicOverlay(float frameOffset) 353 { 354 if (m_OverlayDescriptor.m_Type != DYNAMIC_QUAD) 355 return; 356 357 entity_id_t entityId = GetEntityId(); 358 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), entityId); 359 CmpPtr<ICmpFootprint> cmpFootprint(GetSimContext(), entityId); 360 CmpPtr<ICmpOwnership> cmpOwnership(GetSimContext(), entityId); 361 if (!cmpFootprint || !cmpPosition || !cmpPosition->IsInWorld()) 362 return; 363 364 float rotY; 365 CVector2D position; 366 cmpPosition->GetInterpolatedPosition2D(frameOffset, position.X, position.Y, rotY); 367 368 CmpPtr<ICmpWaterManager> cmpWaterManager(GetSimContext(), SYSTEM_ENTITY); 369 CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY); 370 ENSURE(cmpWaterManager && cmpTerrain); 371 372 CTerrain* terrain = cmpTerrain->GetCTerrain(); 373 ENSURE(terrain); 374 375 // --------------------------------------------------------------------------------- 376 377 CTextureProperties texturePropsBase(m_OverlayDescriptor.m_QuadTexture); 378 texturePropsBase.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); 379 texturePropsBase.SetMaxAnisotropy(4.f); 380 381 CTextureProperties texturePropsMask(m_OverlayDescriptor.m_QuadTextureMask); 382 texturePropsMask.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE); 383 texturePropsMask.SetMaxAnisotropy(4.f); 384 385 ICmpFootprint::EShape fpShape; 386 entity_pos_t fpSize0_fixed, fpSize1_fixed, fpHeight_fixed; 387 cmpFootprint->GetShape(fpShape, fpSize0_fixed, fpSize1_fixed, fpHeight_fixed); 388 389 // --------------------------------------------------------------------------------- 390 391 if (!m_UnitOverlay) 392 m_UnitOverlay = new SOverlayQuad; 393 394 m_UnitOverlay->m_Texture = g_Renderer.GetTextureManager().CreateTexture(texturePropsBase); 395 m_UnitOverlay->m_TextureMask = g_Renderer.GetTextureManager().CreateTexture(texturePropsMask); 396 m_UnitOverlay->m_Color = m_Color; 397 398 // TODO: some code duplication here :< would be nice to factor out getting the corner points of an entity based on its footprint 399 // sizes (and regardless of whether it's a circle or a square) 400 401 float s = sinf(-rotY); 402 float c = cosf(-rotY); 403 CVector2D unitX(c, s); 404 CVector2D unitZ(-s, c); 405 406 float halfSizeX = fpSize0_fixed.ToFloat(); 407 float halfSizeZ = fpSize1_fixed.ToFloat(); 408 if (fpShape == ICmpFootprint::SQUARE) 145 409 { 146 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId());147 if (!cmpPosition)148 return;410 halfSizeX /= 2.0f; 411 halfSizeZ /= 2.0f; 412 } 149 413 150 if (!cmpPosition->IsInWorld()) 151 return; 414 std::vector<CVector2D> points; 415 points.push_back(CVector2D(position + unitX *(-halfSizeX) + unitZ * halfSizeZ)); // top left 416 points.push_back(CVector2D(position + unitX *(-halfSizeX) + unitZ *(-halfSizeZ))); // bottom left 417 points.push_back(CVector2D(position + unitX * halfSizeX + unitZ *(-halfSizeZ))); // bottom right 418 points.push_back(CVector2D(position + unitX * halfSizeX + unitZ * halfSizeZ)); // top right 152 419 153 float x, z, rotY; 154 cmpPosition->GetInterpolatedPosition2D(frameOffset, x, z, rotY); 420 for (int i=0; i < 4; i++) 421 { 422 float quadY = std::max( 423 terrain->GetExactGroundLevel(points[i].X, points[i].Y), 424 cmpWaterManager->GetExactWaterLevel(points[i].X, points[i].Y) 425 ); 155 426 156 CmpPtr<ICmpFootprint> cmpFootprint(GetSimContext(), GetEntityId()); 157 if (!cmpFootprint) 158 { 159 // Default (this probably shouldn't happen) - just render an arbitrary-sized circle 160 SimRender::ConstructCircleOnGround(GetSimContext(), x, z, 2.f, m_Overlay, cmpPosition->IsFloating()); 161 } 162 else 427 m_UnitOverlay->m_Corners[i] = CVector3D(points[i].X, quadY, points[i].Y); 428 } 429 } 430 431 void CCmpSelectable::RenderSubmit(SceneCollector& collector) 432 { 433 // don't render selection overlay if it's not gonna be visible 434 if (m_Color.a > 0) 435 { 436 switch (m_OverlayDescriptor.m_Type) 163 437 { 164 ICmpFootprint::EShape shape; 165 entity_pos_t size0, size1, height; 166 cmpFootprint->GetShape(shape, size0, size1, height); 167 168 if (shape == ICmpFootprint::SQUARE) 169 SimRender::ConstructSquareOnGround(GetSimContext(), x, z, size0.ToFloat(), size1.ToFloat(), rotY, m_Overlay, cmpPosition->IsFloating()); 170 else 171 SimRender::ConstructCircleOnGround(GetSimContext(), x, z, size0.ToFloat(), m_Overlay, cmpPosition->IsFloating()); 438 case STATIC_OUTLINE: 439 { 440 UpdateStaticOverlay(); 441 m_BuildingOverlay->m_Color = m_Color; // done separately so alpha changes don't require a full update call 442 collector.Submit(m_BuildingOverlay); 443 } 444 break; 445 case DYNAMIC_QUAD: 446 { 447 if (m_UnitOverlay) 448 collector.Submit(m_UnitOverlay); 449 } 450 break; 451 default: 452 break; 172 453 } 173 454 } 174 455 175 void RenderSubmit(SceneCollector& collector) 456 // render bounding box debug overlays 457 if (m_AlphaTarget > 0) // so the debug overlay responds immediately to deselection without delay from fading out 176 458 { 177 // (This is only called if a > 0)178 collector.Submit(&m_Overlay);179 180 459 if (ICmpSelectable::ms_EnableDebugOverlays) 181 460 { 182 461 // allocate debug overlays on-demand … … public: 205 484 if (m_DebugSelectionBoxOverlay) SAFE_DELETE(m_DebugSelectionBoxOverlay); 206 485 } 207 486 } 208 } ;487 } 209 488 210 489 REGISTER_COMPONENT_TYPE(Selectable) -
source/simulation2/components/CCmpTemplateManager.cpp
diff --git a/source/simulation2/components/CCmpTemplateManager.cpp b/source/simulation2/components/CCmpTemplateManager.cpp index d512934..73c560f 100644
a b void CCmpTemplateManager::ConstructTemplateActor(const std::string& actorName, C 371 371 372 372 // Initialise the actor's name and make it an Atlas selectable entity. 373 373 std::string name = utf8_from_wstring(CParamNode::EscapeXMLString(wstring_from_utf8(actorName))); 374 std::string xml = "<Entity><VisualActor><Actor>" + name + "</Actor></VisualActor><Selectable><EditorOnly/></Selectable></Entity>"; 374 std::string xml = "<Entity>" 375 "<VisualActor><Actor>" + name + "</Actor></VisualActor>" 376 "<Selectable>" 377 "<EditorOnly/>" 378 "<Overlay><Texture><MainTexture>art/textures/selection/actor.png</MainTexture><MainTextureMask>art/textures/selection/actor_mask.png</MainTextureMask></Texture></Overlay>" 379 "</Selectable>" 380 "</Entity>"; 381 375 382 CParamNode::LoadXMLString(out, xml.c_str()); 376 383 } 377 384 -
source/simulation2/components/CCmpTerritoryManager.cpp
diff --git a/source/simulation2/components/CCmpTerritoryManager.cpp b/source/simulation2/components/CCmpTerritoryManager.cpp index 0ffdd62..c907de1 100644
a b void CCmpTerritoryManager::UpdateBoundaryLines() 618 618 texturePropsMask.SetMaxAnisotropy(2.f); 619 619 CTexturePtr textureMask = g_Renderer.GetTextureManager().CreateTexture(texturePropsMask); 620 620 621 CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY);622 if (!cmpTerrain)623 return;624 CTerrain* terrain = cmpTerrain->GetCTerrain();625 626 621 CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSimContext(), SYSTEM_ENTITY); 627 622 if (!cmpPlayerManager) 628 623 return; … … void CCmpTerritoryManager::UpdateBoundaryLines() 640 635 m_BoundaryLines.push_back(SBoundaryLine()); 641 636 m_BoundaryLines.back().connected = boundaries[i].connected; 642 637 m_BoundaryLines.back().color = color; 643 m_BoundaryLines.back().overlay.m_ Terrain = terrain;638 m_BoundaryLines.back().overlay.m_SimContext = &GetSimContext(); 644 639 m_BoundaryLines.back().overlay.m_TextureBase = textureBase; 645 640 m_BoundaryLines.back().overlay.m_TextureMask = textureMask; 646 641 m_BoundaryLines.back().overlay.m_Color = color; … … void CCmpTerritoryManager::UpdateBoundaryLines() 648 643 m_BoundaryLines.back().overlay.m_Closed = true; 649 644 650 645 SimRender::SmoothPointsAverage(boundaries[i].points, m_BoundaryLines.back().overlay.m_Closed); 651 652 646 SimRender::InterpolatePointsRNS(boundaries[i].points, m_BoundaryLines.back().overlay.m_Closed, m_BorderSeparation); 653 647 654 648 std::vector<float>& points = m_BoundaryLines.back().overlay.m_Coords; -
source/simulation2/components/ICmpSelectable.h
diff --git a/source/simulation2/components/ICmpSelectable.h b/source/simulation2/components/ICmpSelectable.h index c7c8ec2..03d2819 100644
a b struct CColor; 25 25 class ICmpSelectable : public IComponent 26 26 { 27 27 public: 28 /// Batch rendering data ID; used by the selection highlight renderer to efficiently render selection highlights 29 typedef std::size_t renderdata_id; 30 31 enum EOverlayType { 32 /// A single textured quad overlay, intended for entities that move around much, like units (e.g. foot soldiers, etc). 33 DYNAMIC_QUAD, 34 /// A more complex textured line overlay, composed of several textured line segments. Intended for entities that do not 35 /// move often, such as buildings (structures). 36 STATIC_OUTLINE, 37 }; 38 39 struct SOverlayDescriptor 40 { 41 EOverlayType m_Type; 42 std::wstring m_QuadTexture; 43 std::wstring m_QuadTextureMask; 44 std::wstring m_LineTexture; 45 std::wstring m_LineTextureMask; 46 float m_LineThickness; 47 std::wstring m_CornerTexture; 48 std::wstring m_CornerTextureMask; 49 50 SOverlayDescriptor() : m_LineThickness(0) {} 51 52 struct hash : std::unary_function<SOverlayDescriptor, renderdata_id> 53 { 54 renderdata_id operator()(SOverlayDescriptor const& d) const; 55 }; 56 57 bool operator==(const SOverlayDescriptor& other) const; 58 }; 59 28 60 /** 29 61 * Returns true if the entity is only selectable in Atlas editor, e.g. a decorative visual actor. 30 62 */ -
source/simulation2/helpers/Geometry.cpp
diff --git a/source/simulation2/helpers/Geometry.cpp b/source/simulation2/helpers/Geometry.cpp index b357561..7b36a24 100644
a b CFixedVector2D Geometry::GetHalfBoundingBox(CFixedVector2D u, CFixedVector2D v, 45 45 ); 46 46 } 47 47 48 float Geometry::ChordToCentralAngle(const float chordLength, const float radius) 49 { 50 ENSURE(radius > 0); 51 return acosf(1.f - SQR(chordLength)/(2.f*SQR(radius))); // cfr. law of cosines 52 } 53 48 54 fixed Geometry::DistanceToSquare(CFixedVector2D point, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize) 49 55 { 50 56 /* -
source/simulation2/helpers/Geometry.h
diff --git a/source/simulation2/helpers/Geometry.h b/source/simulation2/helpers/Geometry.h index cb925b7..b073099 100644
a b 24 24 */ 25 25 26 26 #include "maths/Fixed.h" 27 #include "maths/MathUtil.h" 27 28 28 29 class CFixedVector2D; 29 30 … … CFixedVector2D GetHalfBoundingBox(CFixedVector2D u, CFixedVector2D v, CFixedVect 53 54 fixed DistanceToSquare(CFixedVector2D point, CFixedVector2D u, CFixedVector2D v, CFixedVector2D halfSize); 54 55 55 56 /** 57 * Given a circle of radius @p radius, and a chord of length @p chordLength on this circle, computes the central angle formed by 58 * connecting the chord's endpoints to the center of the circle. 59 * 60 * @param radius Radius of the circle; must be strictly positive. 61 */ 62 float ChordToCentralAngle(const float chordLength, const float radius); 63 64 /** 56 65 * Find point closest to the given point on the edge of the given square or rectangle. 57 66 * 58 67 * @note Currently assumes the @p u and @p v vectors are perpendicular. -
source/simulation2/helpers/Render.cpp
diff --git a/source/simulation2/helpers/Render.cpp b/source/simulation2/helpers/Render.cpp index 450a28d..712a6d4 100644
a b 19 19 20 20 #include "Render.h" 21 21 22 #include "simulation2/Simulation2.h"23 #include "simulation2/components/ICmpTerrain.h"24 #include "simulation2/components/ICmpWaterManager.h"25 22 #include "graphics/Overlay.h" 26 23 #include "graphics/Terrain.h" 27 24 #include "maths/BoundingBoxAligned.h" 28 25 #include "maths/BoundingBoxOriented.h" 29 26 #include "maths/MathUtil.h" 27 #include "maths/Quaternion.h" 30 28 #include "maths/Vector2D.h" 31 29 #include "ps/Profile.h" 32 #include "maths/Quaternion.h" 30 #include "simulation2/Simulation2.h" 31 #include "simulation2/components/ICmpTerrain.h" 32 #include "simulation2/components/ICmpWaterManager.h" 33 #include "simulation2/helpers/Geometry.h" 33 34 34 35 void SimRender::ConstructLineOnGround(const CSimContext& context, const std::vector<float>& xz, 35 36 SOverlayLine& overlay, bool floating, float heightOffset) … … static CVector2D EvaluateSpline(float t, CVector2D a0, CVector2D a1, CVector2D a 343 344 return p + CVector2D(dp.Y*-offset, dp.X*offset); 344 345 } 345 346 346 void SimRender::InterpolatePointsRNS(std::vector<CVector2D>& points, bool closed, float offset, int segmentSamples )347 void SimRender::InterpolatePointsRNS(std::vector<CVector2D>& points, bool closed, float offset, int segmentSamples /* = 4 */) 347 348 { 348 349 PROFILE("InterpolatePointsRNS"); 349 350 ENSURE(segmentSamples > 0); … … void SimRender::InterpolatePointsRNS(std::vector<CVector2D>& points, bool closed 381 382 382 383 for (size_t i = 0; i < imax; ++i) 383 384 { 384 385 385 // Get the relevant points for this spline segment; each step interpolates the segment between p1 and p2; p0 and p3 are the points 386 386 // before p1 and after p2, respectively; they're needed to compute tangents and whatnot. 387 387 CVector2D p0; // normally points[(i-1+n)%n], but it's a bit more complicated due to open/closed paths -- see below … … void SimRender::ConstructDashedLine(const std::vector<CVector2D>& keyPoints, SDa 521 521 } 522 522 523 523 } 524 525 void SimRender::AngularStepFromChordLen(const float maxChordLength, const float radius, float& out_stepAngle, unsigned& out_numSteps) 526 { 527 float maxAngle = Geometry::ChordToCentralAngle(maxChordLength, radius); 528 out_numSteps = ceilf(float(2*M_PI)/maxAngle); 529 out_stepAngle = float(2*M_PI)/out_numSteps; 530 } 531 532 // TODO: this serves a similar purpose to SplitLine above, but is more general. Also, SplitLine seems to be implemented more 533 // efficiently, might be nice to take some cues from it 534 void SimRender::SubdividePoints(std::vector<CVector2D>& points, float maxSegmentLength, bool closed) 535 { 536 size_t numControlPoints = points.size(); 537 if (numControlPoints < 2) 538 return; 539 540 ENSURE(maxSegmentLength > 0); 541 542 size_t endIndex = numControlPoints; 543 if (!closed && numControlPoints > 2) 544 endIndex--; 545 546 std::vector<CVector2D> newPoints; 547 548 for (size_t i = 0; i < endIndex; i++) 549 { 550 const CVector2D& curPoint = points[i]; 551 const CVector2D& nextPoint = points[(i+1) % numControlPoints]; 552 const CVector2D line(nextPoint - curPoint); 553 CVector2D lineDirection = line.Normalized(); 554 555 // include control point i + a list of intermediate points between i and i + 1 (excluding i+1 itself) 556 newPoints.push_back(curPoint); 557 558 // calculate how many intermediate points are needed so that each segment is of length <= maxSegmentLength 559 float lineLength = line.Length(); 560 size_t numSegments = (size_t) ceilf(lineLength / maxSegmentLength); 561 float segmentLength = lineLength / numSegments; 562 563 for (size_t s = 1; s < numSegments; ++s) // start at one, we already included curPoint 564 { 565 newPoints.push_back(curPoint + lineDirection * (s * segmentLength)); 566 } 567 } 568 569 points.swap(newPoints); 570 } 571 No newline at end of file -
source/simulation2/helpers/Render.h
diff --git a/source/simulation2/helpers/Render.h b/source/simulation2/helpers/Render.h index 93e812d..e95d8e4 100644
a b void ConstructLineOnGround(const CSimContext& context, const std::vector<float>& 76 76 * @param[in,out] overlay Updated overlay line representing this circle. 77 77 * @param[in] floating If true, the circle conforms to water as well. 78 78 * @param[in] heightOffset Height above terrain to offset the circle. 79 * @param heightOffset The vertical offset to apply to points, to raise the line off the terrain a bit. 79 80 */ 80 81 void ConstructCircleOnGround(const CSimContext& context, float x, float z, float radius, 81 82 SOverlayLine& overlay, … … void ConstructSquareOnGround(const CSimContext& context, float x, float z, float 96 97 bool floating, float heightOffset = 0.25f); 97 98 98 99 /** 99 * Constructs a solid outline of an arbitrarily-aligned bo x.100 * Constructs a solid outline of an arbitrarily-aligned bounding @p box. 100 101 * 101 102 * @param[in] box 102 103 * @param[in,out] overlayLine Updated overlay line representing the oriented box. … … void ConstructSquareOnGround(const CSimContext& context, float x, float z, float 104 105 void ConstructBoxOutline(const CBoundingBoxOriented& box, SOverlayLine& overlayLine); 105 106 106 107 /** 107 * Constructs a solid outline of an axis-aligned bounding box.108 * Constructs a solid outline of an axis-aligned bounding @p box. 108 109 * 109 110 * @param[in] bound 110 111 * @param[in,out] overlayLine Updated overlay line representing the AABB. 111 112 */ 112 void ConstructBoxOutline(const CBoundingBoxAligned& bo und, SOverlayLine& overlayLine);113 void ConstructBoxOutline(const CBoundingBoxAligned& box, SOverlayLine& overlayLine); 113 114 114 115 /** 115 116 * Constructs a simple gimbal outline with the given radius and center. … … void ConstructGimbal(const CVector3D& center, float radius, SOverlayLine& out, s 124 125 125 126 /** 126 127 * Constructs 3D axis marker overlay lines for the given coordinate system. 127 * The overlay lines are colored RGB for the XYZ axes, respectively.128 * The XYZ axes are colored RGB, respectively. 128 129 * 129 130 * @param[in] coordSystem Specifies the coordinate system. 130 131 * @param[out] outX,outY,outZ Constructed overlay lines for each axes. … … void InterpolatePointsRNS(std::vector<CVector2D>& points, bool closed, float off 162 163 * @param[in] dashLength Length of a single dash. Must be strictly positive. 163 164 * @param[in] blankLength Length of a single blank between dashes. Must be strictly positive. 164 165 */ 165 void ConstructDashedLine(const std::vector<CVector2D>& linePoints, SDashedLine& dashedLineOut, const float dashLength, const float blankLength); 166 void ConstructDashedLine(const std::vector<CVector2D>& linePoints, SDashedLine& dashedLineOut, 167 const float dashLength, const float blankLength); 168 169 /** 170 * Computes angular step parameters @p out_stepAngle and @p out_numSteps, given a @p maxChordLength on a circle of radius @p radius. 171 * The resulting values satisfy @p out_numSteps * @p out_stepAngle = 2*PI. 172 * 173 * This function is used to find the angular step parameters when drawing a circle outline approximated by several connected chords; 174 * it returns the step angle and number of steps such that the length of each resulting chord is less than or equal to @p maxChordLength. 175 * By stating that each chord cannot be longer than a particular length, a certain level of visual smoothness of the resulting circle 176 * outline can be guaranteed independently of the radius of the outline. 177 * 178 * @param radius Radius of the circle. Must be strictly positive. 179 * @param maxChordLength Desired maximum length of individual chords. Must be strictly positive. 180 */ 181 void AngularStepFromChordLen(const float maxChordLength, const float radius, float& out_stepAngle, unsigned& out_numSteps); 182 183 /** 184 * Subdivides a list of @p points into segments of maximum length @p maxSegmentLength that are of equal size between every two 185 * control points. The resulting subdivided list of points is written back to @p points. 186 * 187 * @param points The list of intermediate points to subdivide. 188 * @param maxSegmentLength The maximum length of a single segment after subdivision. Must be strictly positive. 189 * @param closed Should the provided list of points be treated as a closed shape? If true, the resulting list of points will include 190 * extra subdivided points between the last and the first point. 191 */ 192 void SubdividePoints(std::vector<CVector2D>& points, float maxSegmentLength, bool closed); 166 193 167 194 } // namespace 168 195 -
source/simulation2/tests/test_CmpTemplateManager.h
diff --git a/source/simulation2/tests/test_CmpTemplateManager.h b/source/simulation2/tests/test_CmpTemplateManager.h index d087929..2168e64 100644
a b public: 78 78 const CParamNode* actor = tempMan->LoadTemplate(ent2, "actor|example1", -1); 79 79 TS_ASSERT(actor != NULL); 80 80 TS_ASSERT_WSTR_EQUALS(actor->ToXML(), 81 L"<Selectable><EditorOnly></EditorOnly></Selectable><VisualActor><Actor>example1</Actor><SilhouetteDisplay>false</SilhouetteDisplay><SilhouetteOccluder>false</SilhouetteOccluder></VisualActor>"); 81 L"<Selectable><EditorOnly></EditorOnly><Overlay><Texture><MainTexture>art/textures/selection/actor.png</MainTexture><MainTextureMask>art/textures/selection/actor_mask.png</MainTextureMask></Texture></Overlay></Selectable>" 82 L"<VisualActor><Actor>example1</Actor><SilhouetteDisplay>false</SilhouetteDisplay><SilhouetteOccluder>false</SilhouetteOccluder></VisualActor>"); 82 83 83 84 const CParamNode* preview = tempMan->LoadTemplate(ent2, "preview|unit", -1); 84 85 TS_ASSERT(preview != NULL); -
new file source/tools/selectiontexgen/selectiontexgen.py
diff --git a/source/tools/selectiontexgen/selectiontexgen.py b/source/tools/selectiontexgen/selectiontexgen.py new file mode 100644 index 0000000..a275783
- + 1 """Generates basic square and circle selection overlay textures by parsing all the entity XML files and reading 2 their Footprint components.""" 3 4 # This script uses PyCairo for plotting, since PIL (Python Imaging Library) is absolutely horrible. On Linux, 5 # this should be merely a matter of installing a package (e.g. 'python-cairo' for Debian/Ubuntu), but on Windows 6 # it's kind of tricky and requires some Google-fu. Fortunately, I have saved the working instructions below: 7 # 8 # Grab a Win32 binary from http://ftp.gnome.org/pub/GNOME/binaries/win32/pycairo/1.8/ and install PyCairo using 9 # the installer. The installer extracts the necessary files into Lib\site-packages\cairo within the folder where 10 # Python is installed. There are some extra DLLs which are required to make Cairo work, so we have to get these 11 # as well. 12 # 13 # Head to http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/ and get the binary versions of Cairo 14 # (cairo_1.8.10-3_win32.zip at the time of writing), Fontconfig (fontconfig_2.8.0-2_win32.zip), Freetype 15 # (freetype_2.4.4-1_win32.zip), Expat (expat_2.0.1-1_win32.zip), libpng (libpng_1.4.3-1_win32.zip) and zlib 16 # (zlib_1.2.5-2_win32.zip). Version numbers may vary, so be adaptive! Each ZIP file will contain a bin subfolder 17 # with a DLL file in it. Put the following DLLs in Lib\site-packages\cairo within your Python installation: 18 # 19 # freetype6.dll (from freetype_2.4.4-1_win32.zip) 20 # libcairo-2.dll (from cairo_1.8.10-3_win32.zip) 21 # libexpat-1.dll (from expat_2.0.1-1_win32.zip) 22 # libfontconfig-1.dll (from fontconfig_2.8.0-2_win32.zip) 23 # libpng14-14.dll (from libpng_1.4.3-1_win32.zip) 24 # zlib1.dll (from zlib_1.2.5-2_win32.zip). 25 # 26 # Should be all set now. 27 28 import optparse 29 import sys, os 30 import math 31 import operator 32 import cairo # Requires PyCairo (see notes above) 33 from os.path import * 34 from xml.dom import minidom 35 36 def geqPow2(x): 37 """Returns the smallest power of two that's equal to or greater than x""" 38 return int(2**math.ceil(math.log(x, 2))) 39 40 def generateSelectionTexture(shape, textureW, textureH, outputDir): 41 42 outputBasename = "%dx%d" % (textureW, textureH) 43 44 # size of the image canvas containing the texture (may be larger to ensure power-of-two dimensions) 45 canvasW = geqPow2(textureW) 46 canvasH = geqPow2(textureH) 47 48 # draw texture 49 texture = cairo.ImageSurface(cairo.FORMAT_ARGB32, canvasW, canvasH) 50 textureMask = cairo.ImageSurface(cairo.FORMAT_RGB24, canvasW, canvasH) 51 52 ctxTexture = cairo.Context(texture) 53 ctxTextureMask = cairo.Context(textureMask) 54 55 # fill entire image with transparent pixels 56 ctxTexture.set_source_rgba(1.0, 1.0, 1.0, 0.0) # transparent 57 ctxTexture.rectangle(0, 0, textureW, textureH) 58 ctxTexture.fill() # fill current path 59 60 ctxTextureMask.set_source_rgb(0.0, 0.0, 0.0) # black 61 ctxTextureMask.rectangle(0, 0, canvasW, canvasH) # (!) 62 ctxTextureMask.fill() 63 64 pasteX = (canvasW - textureW)//2 # integer division, floored result 65 pasteY = (canvasH - textureH)//2 # integer division, floored result 66 ctxTexture.translate(pasteX, pasteY) # translate all drawing so that the result is centered 67 ctxTextureMask.translate(pasteX, pasteY) 68 69 if shape == "square": 70 71 rectW = textureW 72 rectH = textureH 73 74 # draw texture (4px white outline, then overlay a 2px black outline) 75 ctxTexture.rectangle(2, 2, rectW-4, rectH-4) 76 ctxTexture.set_line_width(4) 77 ctxTexture.set_source_rgba(1.0, 1.0, 1.0, 1.0) # white 78 ctxTexture.stroke_preserve() # stroke and maintain path 79 ctxTexture.set_line_width(2) 80 ctxTexture.set_source_rgba(0.0, 0.0, 0.0, 1.0) # black 81 ctxTexture.stroke() # stroke and clear path 82 83 # draw mask (2px white) 84 ctxTextureMask.rectangle(2, 2, rectW-4, rectH-4) 85 ctxTextureMask.set_line_width(2) 86 ctxTextureMask.set_source_rgb(1.0, 1.0, 1.0) 87 ctxTextureMask.stroke() 88 89 elif shape == "circle": 90 91 centerX = textureW//2 92 centerY = textureH//2 93 radius = textureW//2 - 2 # allow for 2px on either side so the 4px-wide white stroke can fit 94 95 # draw texture 96 ctxTexture.arc(centerX, centerY, radius, 0, 2*math.pi) 97 ctxTexture.set_line_width(4) 98 ctxTexture.set_source_rgba(1.0, 1.0, 1.0, 1.0) # white 99 ctxTexture.stroke_preserve() # stroke and maintain path 100 ctxTexture.set_line_width(2) 101 ctxTexture.set_source_rgba(0.0, 0.0, 0.0, 1.0) # black 102 ctxTexture.stroke() 103 104 # draw mask 105 ctxTextureMask.arc(centerX, centerY, radius, 0, 2*math.pi) 106 ctxTextureMask.set_line_width(2) 107 ctxTextureMask.set_source_rgb(1.0, 1.0, 1.0) 108 ctxTextureMask.stroke() 109 110 finalOutputDir = outputDir + "/" + shape 111 if not isdir(finalOutputDir): 112 os.makedirs(finalOutputDir) 113 114 print "Generating " + os.path.normcase(finalOutputDir + "/" + outputBasename + ".png") 115 116 texture.write_to_png(finalOutputDir + "/" + outputBasename + ".png") 117 textureMask.write_to_png(finalOutputDir + "/" + outputBasename + "_mask.png") 118 119 120 def generateSelectionTextures(xmlTemplateDir, outputDir, snapSizes = False): 121 122 # recursively list XML files 123 xmlFiles = [] 124 125 for dir, subdirs, basenames in os.walk(xmlTemplateDir): 126 for basename in basenames: 127 filename = join(dir, basename) 128 if filename[-4:] == ".xml": 129 xmlFiles.append(filename) 130 131 textureTypesRaw = set() # set of (type, w, h) tuples (so we can eliminate duplicates) 132 133 # parse the XML files, and look for <Footprint> nodes that are a child of <Entity> and 134 # that do not have the disable attribute defined 135 for xmlFile in xmlFiles: 136 xmlDoc = minidom.parse(xmlFile) 137 rootNode = xmlDoc.childNodes[0] 138 139 # we're only interested in entity templates 140 if not rootNode.nodeName == "Entity": 141 continue 142 143 # check if this entity has a footprint definition 144 rootChildNodes = [n for n in rootNode.childNodes if n.localName is not None] # remove whitespace text nodes 145 footprintNodes = filter(lambda x: x.localName == "Footprint", rootChildNodes) 146 if not len(footprintNodes) == 1: 147 continue 148 149 footprintNode = footprintNodes[0] 150 if footprintNode.hasAttribute("disable"): 151 continue 152 153 # parse the footprint declaration 154 # Footprints can either have either one of these children: 155 # <Circle radius="xx.x" /> 156 # <Square width="xx.x" depth="xx.x"/> 157 # There's also a <Height> node, but we don't care about it here. 158 159 squareNodes = footprintNode.getElementsByTagName("Square") 160 circleNodes = footprintNode.getElementsByTagName("Circle") 161 162 numSquareNodes = len(squareNodes) 163 numCircleNodes = len(circleNodes) 164 165 if not (numSquareNodes + numCircleNodes == 1): 166 print "Invalid Footprint definition: insufficient or too many Square and/or Circle definitions in %s" % xmlFile 167 168 texShape = None 169 texW = None # in world-space units 170 texH = None # in world-space units 171 172 if numSquareNodes == 1: 173 texShape = "square" 174 texW = float(squareNodes[0].getAttribute("width")) 175 texH = float(squareNodes[0].getAttribute("depth")) 176 177 elif numCircleNodes == 1: 178 texShape = "circle" 179 texW = float(circleNodes[0].getAttribute("radius")) 180 texH = texW 181 182 textureTypesRaw.add((texShape, texW, texH)) 183 184 # endfor xmlFiles 185 186 print "Found: %d footprints (%d square, %d circle)" % ( 187 len(textureTypesRaw), 188 len([x for x in textureTypesRaw if x[0] == "square"]), 189 len([x for x in textureTypesRaw if x[0] == "circle"]) 190 ) 191 192 textureTypes = set() 193 194 for type, w, h in textureTypesRaw: 195 if snapSizes: 196 # "snap" texture sizes to close-enough neighbours that will still look good enough so we can get away with fewer 197 # actual textures than there are unique footprint outlines 198 w = 1*math.ceil(w/1) # round up to the nearest world-space unit 199 h = 1*math.ceil(h/1) # round up to the nearest world-space unit 200 201 textureTypes.add((type, w, h)) 202 203 if snapSizes: 204 print "Reduced: %d footprints (%d square, %d circle)" % ( 205 len(textureTypes), 206 len([x for x in textureTypes if x[0] == "square"]), 207 len([x for x in textureTypes if x[0] == "circle"]) 208 ) 209 210 # create list from texture types set (so we can sort and have prettier output) 211 textureTypes = sorted(list(textureTypes), key=operator.itemgetter(0,1,2)) # sort by the first tuple element, then by the second, then the third 212 213 # ------------------------------------------------------------------------------------ 214 # compute the size of the actual texture we want to generate (in px) 215 216 scale = 8 # world-space-units-to-pixels scale 217 for type, w, h in textureTypes: 218 219 # if we have a circle, update the w and h so that they're the full width and height of the texture 220 # and not just the radius 221 if type == "circle": 222 assert w == h 223 w *= 2 224 h *= 2 225 226 w = int(math.ceil(w*scale)) 227 h = int(math.ceil(h*scale)) 228 229 # apply a minimum size for really small textures (otherwise you get really ugly textures ingame) 230 w = max(24, w) 231 h = max(24, h) 232 233 generateSelectionTexture(type, w, h, outputDir) 234 235 236 if __name__ == "__main__": 237 238 parser = optparse.OptionParser(usage="Usage: %prog [filenames]") 239 240 parser.add_option("--template-dir", type="str", default=None, help="Path to simulation template XML definition folder. Will be searched recursively for templates containing Footprint definitions. If not specified and this script is run from its directory, it will be automatically determined.") 241 parser.add_option("--output-dir", type="str", default=".", help="Output directory. Will be created if it does not already exist.") 242 243 (options, args) = parser.parse_args() 244 245 templateDir = options.template_dir 246 if templateDir is None: 247 248 scriptDir = dirname(abspath(__file__)) 249 250 # 'autodetect' location if run from its own dir 251 if normcase(scriptDir).replace('\\', '/').endswith("source/tools/selectiontexgen"): 252 templateDir = "../../../binaries/data/mods/public/simulation/templates" 253 else: 254 print "No template dir specified; use the --template-dir command line argument." 255 sys.exit() 256 257 # check if the template dir exists 258 templateDir = abspath(templateDir) 259 if not isdir(templateDir): 260 print "No such template directory: %s" % templateDir 261 sys.exit() 262 263 # check if the output dir exists, create it if needed 264 outputDir = abspath(options.output_dir) 265 print outputDir 266 if not isdir(outputDir): 267 print "Creating output directory: %s" % outputDir 268 os.makedirs(outputDir) 269 270 print "Template directory:\t%s" % templateDir 271 print "Output directory: \t%s" % outputDir 272 print "------------------------------------------------" 273 274 generateSelectionTextures(templateDir, outputDir) 275 No newline at end of file