7#include "zeroerr/assert.h"
12#include <unordered_map>
38 float z =
d->zoom <= 0.f ? 1e-4f :
d->zoom;
39 return (screenX - viewW * 0.5f) /
z +
d->x;
44 float z =
d->zoom <= 0.f ? 1e-4f :
d->zoom;
45 return (screenY - viewH * 0.5f) /
z +
d->y;
50 float z =
d->zoom <= 0.f ? 1e-4f :
d->zoom;
51 return (worldX -
d->x) *
z + viewW * 0.5f;
56 float z =
d->zoom <= 0.f ? 1e-4f :
d->zoom;
57 return (worldY -
d->y) *
z + viewH * 0.5f;
66float clampZoom(
float z) {
return z <= 0.f ? 1e-4f :
z; }
77ViewCam fromEntity(Camera2D *ent) {
86 v.ambientR =
d->ambientR;
87 v.ambientG =
d->ambientG;
88 v.ambientB =
d->ambientB;
92void applyCamera(
float wx,
float wy,
float ww,
float wh,
const ViewCam &cam,
int viewW,
int viewH,
93 float &sx,
float &sy,
float &sw,
float &sh) {
103 const float z = clampZoom(cam.zoom);
105 sx = (wx - cam.x) *
z +
float(viewW) * 0.5f;
106 sy = (wy - cam.y) *
z +
float(viewH) * 0.5f;
116void collectLights(Canvas *canvasKey, std::vector<PackedLight> &out) {
118 if (ecs::current()->getManager<Light2D>() ==
nullptr)
return;
119 auto view = ecs::View<Light2D, Light2D::Data>();
120 for (
auto it =
view.begin(); it !=
view.end(); ++it) {
122 if (!
d->enabled)
continue;
123 if (
d->canvas != canvasKey)
continue;
126 pl.isPoint = (
d->type !=
"dir");
129 std::stable_sort(out.begin(), out.end(), [](
const PackedLight &
a,
const PackedLight &
b) {
130 if (a.isPoint != b.isPoint) return a.isPoint && !b.isPoint;
131 return a.data->intensity > b.data->intensity;
137Lighting2DUBO packLights(
const std::vector<PackedLight> &lights,
const ViewCam &cam,
int viewW,
140 ubo.ambient = glm::vec4(cam.ambientR, cam.ambientG, cam.ambientB, 0.f);
141 ubo.meta = glm::vec4(
float(lights.size()),
float(viewW),
float(viewH), 0.f);
142 for (
size_t i = 0; i < lights.size(); ++i) {
143 const auto *
d = lights[i].data;
144 Light2DGpu &g = ubo.lights[i];
145 g.color = glm::vec4(
d->r *
d->intensity,
d->g *
d->intensity,
d->b *
d->intensity, 1.f);
147 float lx =
d->x, ly =
d->y;
148 float lr =
d->radius;
150 const float z = clampZoom(cam.zoom);
151 lx = (
d->x - cam.x) *
z +
float(viewW) * 0.5f;
152 ly = (
d->y - cam.y) *
z +
float(viewH) * 0.5f;
155 g.posRadius = glm::vec4(lx, ly, 0.f, lr);
157 float dx =
d->dx, dy =
d->dy;
158 const float len = std::sqrt(dx * dx + dy * dy);
166 g.posRadius = glm::vec4(dx, dy, 0.f, 0.f);
172Color modulateUnlit(
Color base,
float cx,
float cy,
bool receiveLight,
const Lighting2DUBO &ubo) {
173 if (!receiveLight)
return base;
174 glm::vec3 lit(ubo.ambient.r, ubo.ambient.g, ubo.ambient.b);
175 const int count = int(ubo.meta.x + 0.5f);
176 for (
int i = 0; i < count; ++i) {
177 const auto &L = ubo.lights[i];
178 glm::vec3 col(L.color.r, L.color.g, L.color.b);
179 if (L.posRadius.w <= 0.f) {
183 const float dx = L.posRadius.x -
cx;
184 const float dy = L.posRadius.y -
cy;
185 const float dist = std::sqrt(dx * dx + dy * dy);
186 float atten = 1.f - dist / std::max(L.posRadius.w, 1.f);
187 if (atten < 0.f) atten = 0.f;
192 return Color(base.r * lit.r, base.g * lit.g, base.b * lit.b, base.a);
198 std::unordered_map<Canvas *, Camera2D *> defaultCam;
199 if (ecs::current()->getManager<Camera2D>() !=
nullptr) {
200 auto camView = ecs::View<Camera2D, Camera2D::Data>();
201 for (
auto it = camView.begin(); it != camView.end(); ++it) {
203 if (!
data->active)
continue;
204 ASSERT(
data->entity !=
nullptr);
205 if (!
data->entity)
continue;
207 if (defaultCam.find(key) == defaultCam.end()) defaultCam[key] =
data->entity;
211 auto view = ecs::View<Renderable2D, Renderable2D::Transform2D, Renderable2D::Sprite>();
212 for (
auto it =
view.begin(); it !=
view.end(); ++it) {
214 if (!sp->visible)
continue;
218 auto found = defaultCam.find(sp->canvas);
219 camEnt = (found != defaultCam.end()) ? found->second :
nullptr;
222 ViewCam cam = fromEntity(camEnt);
226 item.
w = sp->width * xf->sx;
227 item.
h = sp->height * xf->sy;
228 item.
depthY = xf->y + sp->height * xf->sy;
229 item.
color =
Color(sp->r, sp->g, sp->b, sp->a);
230 item.
layer = sp->layer;
232 item.
normal = sp->normalTexture;
233 item.
quad = sp->quad;
246 item.
litPath = sp->receiveLight && sp->normalTexture !=
nullptr && sp->texture !=
nullptr &&
247 sp->shader ==
nullptr;
261 std::unordered_map<Canvas *, Camera2D *> defaultCam;
262 if (ecs::current()->getManager<Camera2D>() !=
nullptr) {
263 auto camView = ecs::View<Camera2D, Camera2D::Data>();
264 for (
auto it = camView.begin(); it != camView.end(); ++it) {
266 if (!
data->active)
continue;
267 if (!
data->entity)
continue;
269 if (defaultCam.find(key) == defaultCam.end()) defaultCam[key] =
data->entity;
273 Canvas *current =
reinterpret_cast<Canvas *
>(
static_cast<uintptr_t
>(1));
275 for (
size_t i = 0; i < items.size(); ++i) {
276 Canvas *next = items[i].canvas;
277 if (i == 0 || next != current) {
280 auto defIt = defaultCam.find(next);
281 if (defIt != defaultCam.end()) {
282 groupCam = fromEntity(defIt->second);
283 clearCol = groupCam.clearColor;
284 }
else if (items[i].camValid) {
285 groupCam.valid =
true;
286 groupCam.x = items[i].camX;
287 groupCam.y = items[i].camY;
288 groupCam.zoom = items[i].camZoom;
289 groupCam.clearColor = items[i].camClear;
290 groupCam.ambientR = items[i].camAmbientR;
291 groupCam.ambientG = items[i].camAmbientG;
292 groupCam.ambientB = items[i].camAmbientB;
293 clearCol = groupCam.clearColor;
299 if (present) gfx.
clear(clearCol, std::nullopt, std::nullopt);
304 std::vector<PackedLight> packed;
305 collectLights(next, packed);
306 currentLights = packLights(packed, groupCam, viewW, viewH);
310 const auto &it = items[i];
316 cam.zoom = it.camZoom;
317 }
else if (it.camera) {
318 cam = fromEntity(it.camera);
320 int viewW = it.canvas ? it.canvas->getWidth() : gfx.
getWidth();
321 int viewH = it.canvas ? it.canvas->getHeight() : gfx.
getHeight();
322 float sx, sy, sw, sh;
323 applyCamera(it.x, it.y, it.w, it.h, cam, viewW, viewH, sx, sy, sw, sh);
325 float u0 = it.hasUV ? it.u0 : 0.f;
326 float v0 = it.hasUV ? it.v0 : 0.f;
327 float u1 = it.hasUV ? it.u1 : 1.f;
328 float v1 = it.hasUV ? it.v1 : 1.f;
329 if (!it.hasUV && it.quad && it.texture)
330 it.quad->getUV(it.texture->getWidth(), it.texture->getHeight(), u0, v0, u1, v1);
336 gfx.
drawTexturedRectLitUV(it.texture, it.normal, sx, sy, sw, sh, u0, v0, u1, v1,
338 }
else if (it.texture) {
340 if (it.receiveLight && !it.normal)
341 c = modulateUnlit(
c, sx + sw * 0.5f, sy + sh * 0.5f,
true, currentLights);
344 if (it.rotation != 0.f) {
346 it.shader ?
"shader" :
"textured");
348 sy + sh * 0.5f, sw, sh, it.rotation, u0, v0, u1,
349 v1,
c, it.rotatedUV, it.blend);
352 gfx.
drawTexturedRectShaderUV(it.texture, it.shader, sx, sy, sw, sh, u0, v0, u1, v1,
c,
353 it.rotatedUV, it.blend);
358 c = modulateUnlit(
c, sx + sw * 0.5f, sy + sh * 0.5f,
true, currentLights);
360 if (it.rotation != 0.f)
378 std::vector<DrawItem2D> items;
RAII pass scope for C++ call sites.
Declarative 2D camera (viewport center + zoom).
float screenToWorldY(float screenX, float screenY, float viewW, float viewH)
float worldToScreenY(float worldX, float worldY, float viewW, float viewH)
float worldToScreenX(float worldX, float worldY, float viewW, float viewH)
float screenToWorldX(float screenX, float screenY, float viewW, float viewH)
Convert screen pixel (origin top-left of viewport) to world coordinates. viewW/viewH are the current ...
void setAmbient(float r, float g, float b)
void setPosition(float x, float y)
World-space look-at center and zoom (1 = identity).
virtual int getWidth() const =0
virtual void clear(std::optional< Color > color, std::optional< int > stencil, std::optional< double > depth)=0
virtual int getHeight() const =0
virtual void drawTexturedRectShaderUV(Texture *texture, Shader *shader, float x, float y, float w, float h, float u0, float v0, float u1, float v1, const Color &color, bool rotatedUV=false, BlendMode blend=BlendMode::Alpha)=0
UV draw with an explicit Shader (nullptr = default textured pipeline).
Color getBackgroundColor() const
virtual void setLighting2D(const Lighting2DUBO &ubo)=0
Upload per-frame / per-canvas 2D lighting constants for subsequent lit draws.
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...
virtual void drawSolidRectRotated(float cx, float cy, float w, float h, float degrees, const Color &color, BlendMode blend=BlendMode::Alpha)=0
Rotated solid quad degrees clockwise (screen Y-down) around (cx, cy).
virtual void setCanvas(Canvas *canvas)=0
nullptr or this → screen. Switching flushes pending draws to the previous target.
virtual void drawSolidRect(float x, float y, float w, float h, const Color &color, BlendMode blend=BlendMode::Alpha)=0
Internal immediate-mode helper used by RenderSystem / Batcher.
virtual void drawTexturedRectLitUV(Texture *albedo, Texture *normal, float x, float y, float w, float h, float u0, float v0, float u1, float v1, const Color &color)=0
Lit 2D draw (albedo + normal map). Uses Lighting2DUBO from setLighting2D. normal may be null → treate...
void getUV(int texW, int texH, float &u0, float &v0, float &u1, float &v1) const
Convert pixel rect to normalized UVs for a texture of size texW×texH.
static void render(Graphics &gfx)
Full sprite pass + present (existing tests / sprite-only scenes).
static void collectSprites(std::vector< DrawItem2D > &out)
Append visible Renderable2D sprites into a shared queue.
static void drawItems(Graphics &gfx, std::vector< DrawItem2D > &items, bool present)
Sort and draw items. If present=true, calls gfx.present() at the end. Map::render uses present=false ...
void setCastOcclusion(bool cast)
void rtBind(const char *kind, const char *name)
void rtTarget(const char *name)
void rtPassBegin(const char *name)
void rtDraw(const char *api, const char *detail=nullptr)
void rtPassEnd(const char *name)
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
glm::vec4 Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
void sortDrawItems2D(std::vector< DrawItem2D > &items)
Shared 2D draw queue item (sprites + tiles).
float camX
Screen-space camera already resolved; if cameraEntity set, RenderSystem resolves.
static constexpr int kMaxLights