载入中...
搜索中...
未找到
SpriteStack2D.cpp
浏览该文件的文档.
2
3#include "common/Exception.h"
4#include "graphics/Color.h"
5#include "graphics/Graphics.h"
7#include "image/ImageData.h"
8
9#include <algorithm>
10#include <cmath>
11#include <functional>
12#include <simplesquirrel/simplesquirrel.hpp>
13
14namespace eve::spritestack {
15namespace {
16float clamp01(float value) { return std::max(0.f, std::min(1.f, value)); }
17}
18
20 if (count < 0) throw eve::Exception("SpriteStack2D.setLayerCount: count must be >= 0");
21 layerCount_ = count;
22 layers_.assign(size_t(count), Layer{});
23 bumpVersion();
24}
25
26int SpriteStack2D::getLayerCount() const { return layerCount_; }
27
29 if (index < 0 || index >= layerCount_)
30 throw eve::Exception("SpriteStack2D.setLayerTexture: index %d out of range [0,%d)", index,
31 layerCount_);
32 layers_[size_t(index)] = Layer{texture, 0.f, 0.f, 1.f, 1.f};
33 bumpVersion();
34}
35
37 if (index < 0 || index >= layerCount_) return nullptr;
38 return layers_[size_t(index)].texture;
39}
40
42 if (!gfx) throw eve::Exception("SpriteStack2D.setLayerImage: null graphics");
43 if (!img) throw eve::Exception("SpriteStack2D.setLayerImage: null ImageData");
44 setLayerTexture(gfx->newTextureFromImageData(img, false, false), index);
45}
46
47void SpriteStack2D::setLayerFile(graphics::Graphics *gfx, const std::string &path, int index) {
48 if (!gfx) throw eve::Exception("SpriteStack2D.setLayerFile: null graphics");
50}
51
53 int layerCount) {
54 if (!gfx) throw eve::Exception("SpriteStack2D.setLayersFromAtlas: null graphics");
55 if (!atlas) throw eve::Exception("SpriteStack2D.setLayersFromAtlas: null atlas");
56 if (layerCount <= 0) throw eve::Exception("SpriteStack2D.setLayersFromAtlas: count must be > 0");
57 setLayerCount(layerCount);
58 for (int i = 0; i < layerCount; ++i) {
59 const float u0 = float(i) / float(layerCount);
60 const float u1 = float(i + 1) / float(layerCount);
61 layers_[size_t(i)] = Layer{atlas, u0, 0.f, u1, 1.f};
62 }
63 bumpVersion();
64}
65
67 if (thickness <= 0.f) throw eve::Exception("SpriteStack2D.setThickness: must be > 0");
68 thickness_ = thickness;
69 bumpVersion();
70}
71float SpriteStack2D::getThickness() const { return thickness_; }
72
74 if (width <= 0.f || height <= 0.f) throw eve::Exception("SpriteStack2D.setSize: size must be > 0");
75 width_ = width;
76 height_ = height;
77 bumpVersion();
78}
79float SpriteStack2D::getWidth() const { return width_; }
80float SpriteStack2D::getHeight() const { return height_; }
81
82void SpriteStack2D::setPosition(float x, float y) {
83 x_ = x;
84 y_ = y;
85 bumpVersion();
86}
88 rotation_ = degrees;
89 bumpVersion();
90}
91void SpriteStack2D::setTint(float r, float g, float b, float a) {
92 tintR_ = clamp01(r);
93 tintG_ = clamp01(g);
94 tintB_ = clamp01(b);
95 tintA_ = clamp01(a);
96 bumpVersion();
97}
98void SpriteStack2D::setVisible(bool visible) { visible_ = visible; }
99bool SpriteStack2D::getVisible() const { return visible_; }
100
101void SpriteStack2D::setShadowEnabled(bool enabled) { shadowEnabled_ = enabled; }
102bool SpriteStack2D::getShadowEnabled() const { return shadowEnabled_; }
103void SpriteStack2D::setShadowOpacity(float opacity) { shadowOpacity_ = clamp01(opacity); }
105 shadowOffsetX_ = x;
106 shadowOffsetY_ = y;
107}
108void SpriteStack2D::setOutline(float width, float r, float g, float b) {
109 outlineWidth_ = std::max(0.f, width);
110 setOutlineColor(r, g, b);
111}
112float SpriteStack2D::getOutlineWidth() const { return outlineWidth_; }
113void SpriteStack2D::setOutlineColor(float r, float g, float b) {
114 outlineR_ = clamp01(r);
115 outlineG_ = clamp01(g);
116 outlineB_ = clamp01(b);
117}
118
119void SpriteStack2D::draw(graphics::Graphics *gfx, graphics::Camera2D *camera) const {
120 if (!visible_ || layerCount_ <= 0) return;
121 float cx = x_;
122 float baseY = y_;
123 float scale = 1.f;
124 if (camera) {
125 const float viewW = float(gfx->getWidth());
126 const float viewH = float(gfx->getHeight());
127 cx = camera->worldToScreenX(x_, y_, viewW, viewH);
128 baseY = camera->worldToScreenY(x_, y_, viewW, viewH);
129 scale = camera->getZoom();
130 }
131 const auto queueLayer = [&](const Layer &layer, float x, float y, float w, float h,
132 const graphics::Color &tint) {
133 gfx->drawTexturedRectShaderUVRotated(layer.texture, nullptr, x, y, w, h, rotation_,
134 layer.u0, layer.v0, layer.u1, layer.v1, tint);
135 };
136 if (shadowEnabled_) {
137 const graphics::Color shadow(0.f, 0.f, 0.f, shadowOpacity_ * tintA_);
138 for (int i = 0; i < layerCount_; ++i) {
139 const Layer &layer = layers_[size_t(i)];
140 if (!layer.texture) continue;
141 queueLayer(layer, cx + shadowOffsetX_ * scale,
142 baseY + shadowOffsetY_ * scale - float(i) * thickness_ * scale,
143 width_ * scale, height_ * scale, shadow);
144 }
145 }
146 if (outlineWidth_ > 0.f) {
147 const graphics::Color outline(outlineR_, outlineG_, outlineB_, tintA_);
148 for (int i = 0; i < layerCount_; ++i) {
149 const Layer &layer = layers_[size_t(i)];
150 if (!layer.texture) continue;
151 queueLayer(layer, cx, baseY - float(i) * thickness_ * scale,
152 width_ * scale + outlineWidth_ * 2.f,
153 height_ * scale + outlineWidth_ * 2.f, outline);
154 }
155 }
156 const graphics::Color tint(tintR_, tintG_, tintB_, tintA_);
157 for (int i = 0; i < layerCount_; ++i) {
158 const Layer &layer = layers_[size_t(i)];
159 if (!layer.texture) continue;
160 queueLayer(layer, cx, baseY - float(i) * thickness_ * scale,
161 width_ * scale, height_ * scale, tint);
162 }
163}
164
166 if (!gfx) throw eve::Exception("SpriteStack2D.render: null graphics");
167 draw(gfx, nullptr);
168}
170 if (!gfx) throw eve::Exception("SpriteStack2D.renderWithCamera: null graphics");
171 draw(gfx, camera);
172}
173
175 if (!stack) throw eve::Exception("SpriteStackBatch.add: null stack");
176 if (std::find(stacks_.begin(), stacks_.end(), stack) == stacks_.end()) stacks_.push_back(stack);
177}
179 stacks_.erase(std::remove(stacks_.begin(), stacks_.end(), stack), stacks_.end());
180}
181void SpriteStackBatch::clear() { stacks_.clear(); }
182int SpriteStackBatch::getStackCount() const { return int(stacks_.size()); }
184 if (!gfx) throw eve::Exception("SpriteStackBatch.render: null graphics");
185 renderWithCamera(gfx, nullptr);
186}
188 if (!gfx) throw eve::Exception("SpriteStackBatch.renderWithCamera: null graphics");
189 for (SpriteStack2D *stack : stacks_) if (stack) stack->draw(gfx, camera);
190}
191
193
195 if (!gfx) throw eve::Exception("SpriteStack.newStack: null graphics");
196 return new SpriteStack2D();
197}
199 if (!gfx) throw eve::Exception("SpriteStack.newBatch: null graphics");
200 return new SpriteStackBatch();
201}
202
203std::vector<image::ImageData *> SpriteStack::slicePrimitive(const std::string &kind, int layerCount,
204 int imageW, int imageH,
205 const std::string &axis,
206 float thickness) {
208 options.layerCount = layerCount;
209 options.imageW = imageW;
210 options.imageH = imageH;
211 options.axis = axis;
212 options.thickness = thickness;
214}
215
216void SpriteStack::expose(ssq::Table &table) {
217 auto cls = table.addClass(name, SpriteStack::create, false);
218 expose(cls);
219 auto stack = table.addClass<SpriteStack2D>(
220 "SpriteStack2D", std::function<SpriteStack2D *()>([]() { return nullptr; }), true);
221 stack.addFunc("setLayerCount", &SpriteStack2D::setLayerCount);
222 stack.addFunc("getLayerCount", &SpriteStack2D::getLayerCount);
223 stack.addFunc("setLayerTexture", &SpriteStack2D::setLayerTexture);
224 stack.addFunc("getLayerTexture", &SpriteStack2D::getLayerTexture);
225 stack.addFunc("setLayerImage", &SpriteStack2D::setLayerImage);
226 stack.addFunc("setLayerFile", &SpriteStack2D::setLayerFile);
227 stack.addFunc("setLayersFromAtlas", &SpriteStack2D::setLayersFromAtlas);
228 stack.addFunc("setThickness", &SpriteStack2D::setThickness);
229 stack.addFunc("getThickness", &SpriteStack2D::getThickness);
230 stack.addFunc("setSize", &SpriteStack2D::setSize);
231 stack.addFunc("getWidth", &SpriteStack2D::getWidth);
232 stack.addFunc("getHeight", &SpriteStack2D::getHeight);
233 stack.addFunc("setPosition", &SpriteStack2D::setPosition);
234 stack.addFunc("setRotation", &SpriteStack2D::setRotation);
235 stack.addFunc("setTint", &SpriteStack2D::setTint);
236 stack.addFunc("setVisible", &SpriteStack2D::setVisible);
237 stack.addFunc("getVisible", &SpriteStack2D::getVisible);
238 stack.addFunc("setShadowEnabled", &SpriteStack2D::setShadowEnabled);
239 stack.addFunc("getShadowEnabled", &SpriteStack2D::getShadowEnabled);
240 stack.addFunc("setShadowOpacity", &SpriteStack2D::setShadowOpacity);
241 stack.addFunc("setShadowOffset", &SpriteStack2D::setShadowOffset);
242 stack.addFunc("setOutline", &SpriteStack2D::setOutline);
243 stack.addFunc("getOutlineWidth", &SpriteStack2D::getOutlineWidth);
244 stack.addFunc("setOutlineColor", &SpriteStack2D::setOutlineColor);
245 stack.addFunc("render", &SpriteStack2D::render);
246 stack.addFunc("renderWithCamera", &SpriteStack2D::renderWithCamera);
247
248 auto batch = table.addClass<SpriteStackBatch>(
249 "SpriteStackBatch", std::function<SpriteStackBatch *()>([]() { return nullptr; }), true);
250 batch.addFunc("add", &SpriteStackBatch::add);
251 batch.addFunc("remove", &SpriteStackBatch::remove);
252 batch.addFunc("clear", &SpriteStackBatch::clear);
253 batch.addFunc("getStackCount", &SpriteStackBatch::getStackCount);
254 batch.addFunc("render", &SpriteStackBatch::render);
255 batch.addFunc("renderWithCamera", &SpriteStackBatch::renderWithCamera);
256}
257
258void SpriteStack::expose(ssq::Class &cls) {
259 cls.addFunc("getName", &SpriteStack::getName);
260 cls.addFunc("newStack", &SpriteStack::newStack);
261 cls.addFunc("newBatch", &SpriteStack::newBatch);
262 cls.addFunc("slicePrimitive", &SpriteStack::slicePrimitive);
263#if defined(EVE_SPRITESTACK_MODEL3D)
265#endif
266}
267
268} // namespace eve::spritestack
double value
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float cx
Definition CardTypes.cpp:33
float degrees
Definition CardTypes.cpp:35
float thickness
Definition CaveMesh.cpp:83
HSQOBJECT cls
Definition ECS.cpp:21
tensor::Graph g
Definition GpuGraph.cpp:7
float camera[2]
glm::vec4 tint
double r
int h
std::uint32_t height
std::uint32_t width
TokenKind kind
std::array< float, 3 > scale
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
MeshVfxBatchedDraw draw
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
TileLayer * layer
std::string path
Definition PlayHost.cpp:110
std::uint32_t count
const SquirrelValueOptions & options
float opacity
bool visible
uint32_t index
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
virtual std::string getName() const =0
Returns the name.
Declarative 2D camera (viewport center + zoom).
int getWidth() const
Returns the width.
Definition Graphics.h:502
virtual void drawTexturedRectShaderUVRotated(Texture *texture, Shader *shader, float cx, float cy, float w, float h, float degrees, float u0, float v0, float u1, float v1, const Color &color, bool rotatedUV=false, BlendMode blend=BlendMode::Alpha)=0
UV draw rotated degrees clockwise (screen Y-down) around the rect center. texture may be null → solid...
Texture * newTextureFromImageData(image::ImageData *data, bool repeatU=false, bool repeatV=false)
Creates a texture from image data. @ownership Caller deletes unless documented otherwise.
virtual Texture * newTextureFromFile(const std::string &filename)=0
Creates a texture from file. @ownership Caller deletes unless documented otherwise.
int getHeight() const
Returns the height.
Definition Graphics.h:504
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:18
Represents raw pixel data.
Definition ImageData.h:38
Pure-2D sprite stack made from horizontal RGBA cross-sections.
Definition SpriteStack.h:61
void setLayersFromAtlas(graphics::Graphics *gfx, graphics::Texture *atlas, int layerCount)
Sets the layers from atlas.
void setLayerCount(int count)
Sets the layer count.
void setShadowOpacity(float opacity)
Sets the shadow opacity.
float getHeight() const
Returns the height.
void setOutline(float width, float r=0.f, float g=0.f, float b=0.f)
Draw enlarged dark copies behind the layers.
bool getVisible() const
Returns the visible.
void setThickness(float thickness)
Upward 2D offset between adjacent layers.
void render(graphics::Graphics *gfx) const
Queue the stack into Graphics' normal 2D renderer.
float getWidth() const
Returns the width.
void renderWithCamera(graphics::Graphics *gfx, graphics::Camera2D *camera) const
Renders with camera.
void setShadowEnabled(bool enabled)
Draw a cheap 2D contact shadow behind the stack.
int getLayerCount() const
Returns the layer count.
void setShadowOffset(float x, float y)
Sets the shadow offset.
graphics::Texture * getLayerTexture(int index) const
Returns the layer texture.
void setOutlineColor(float r, float g, float b)
Sets the outline color.
void setRotation(float degrees)
Rotate every slice around its common 2D center, in degrees.
float getOutlineWidth() const
Returns the outline width.
void setTint(float r, float g, float b, float a=1.f)
Sets the tint.
float getThickness() const
Returns the thickness.
void setSize(float width, float height)
Display size of every layer in 2D units.
void setLayerImage(graphics::Graphics *gfx, image::ImageData *img, int index)
Sets the layer image.
void setVisible(bool visible)
Sets the visible.
void setPosition(float x, float y)
Sets the position.
void setLayerFile(graphics::Graphics *gfx, const std::string &path, int index)
Sets the layer file.
void setLayerTexture(graphics::Texture *texture, int index)
Sets the layer texture.
bool getShadowEnabled() const
Returns the shadow enabled.
Collection of 2D stacks; Graphics performs texture batching.
void renderWithCamera(graphics::Graphics *gfx, graphics::Camera2D *camera) const
Renders with camera.
int getStackCount() const
Returns the stack count.
void remove(SpriteStack2D *stack)
Removes remove.
void add(SpriteStack2D *stack)
Adds add.
void render(graphics::Graphics *gfx) const
Renders render.
SpriteStack module: horizontal slice baking plus pure-2D rendering.
SpriteStackBatch * newBatch(graphics::Graphics *gfx)
Creates a batch. @ownership Caller deletes unless documented otherwise.
std::vector< image::ImageData * > slicePrimitive(const std::string &kind, int layerCount, int imageW, int imageH, const std::string &axis, float thickness)
Slice primitive.
SpriteStack2D * newStack(graphics::Graphics *gfx)
Creates a stack. @ownership Caller deletes unless documented otherwise.
eve::Color Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13
void exposeSpriteStackModelBindings(ssq::Class &cls)
Register sliceModel when SpriteStackModel.cpp is linked (model3d on).
std::vector< image::ImageData * > slicePrimitiveToLayers(const std::string &kind, const SliceOptions &opt)
Slice primitive to layers.
bool enabled
Options for baking a mesh into equal-sized RGBA sprite layers.
Definition SpriteStack.h:36