ppsspp/Common/Render/DrawBuffer.h

218 lines
7.1 KiB
C
Raw Normal View History

2012-03-24 23:39:19 +01:00
#pragma once
2012-03-31 11:16:13 +02:00
// "Immediate mode"-lookalike buffered drawing. Very fast way to draw 2D.
#include <vector>
#include <cstdint>
#include "Common/Data/Color/RGBAUtil.h"
#include "Common/Render/TextureAtlas.h"
#include "Common/Math/geom2d.h"
#include "Common/Math/lin/matrix4x4.h"
#include "Common/GPU/thin3d.h"
2012-03-24 23:39:19 +01:00
struct Atlas;
2021-09-09 11:58:02 +02:00
enum {
// Enough?
MAX_VERTS = 65536,
};
2012-03-24 23:39:19 +01:00
enum {
2013-01-10 09:42:02 +01:00
ALIGN_LEFT = 0,
ALIGN_RIGHT = 16,
ALIGN_TOP = 0,
ALIGN_BOTTOM = 1,
ALIGN_HCENTER = 4,
ALIGN_VCENTER = 8,
ALIGN_VBASELINE = 32, // text only, possibly not yet working
ALIGN_CENTER = ALIGN_HCENTER | ALIGN_VCENTER,
ALIGN_TOPLEFT = ALIGN_TOP | ALIGN_LEFT,
ALIGN_TOPRIGHT = ALIGN_TOP | ALIGN_RIGHT,
ALIGN_BOTTOMLEFT = ALIGN_BOTTOM | ALIGN_LEFT,
ALIGN_BOTTOMRIGHT = ALIGN_BOTTOM | ALIGN_RIGHT,
// Only for text drawing
ROTATE_90DEG_LEFT = 256,
ROTATE_90DEG_RIGHT = 512,
ROTATE_180DEG = 1024,
// For "uncachable" text like debug log.
// Avoids using system font drawing as it's too slow.
// Not actually used here but is reserved for whatever system wraps DrawBuffer.
FLAG_DYNAMIC_ASCII = 2048,
FLAG_NO_PREFIX = 4096, // means to not process ampersands
FLAG_WRAP_TEXT = 8192,
FLAG_ELLIPSIZE_TEXT = 16384,
2012-03-24 23:39:19 +01:00
};
2016-12-25 18:18:19 +01:00
namespace Draw {
class Pipeline;
2016-12-25 18:18:19 +01:00
}
2012-03-24 23:39:19 +01:00
struct GradientStop {
2013-01-10 09:42:02 +01:00
float t;
uint32_t color;
2012-03-24 23:39:19 +01:00
};
class TextDrawer;
class DrawBuffer {
2012-05-08 22:04:24 +02:00
public:
2013-01-10 09:42:02 +01:00
DrawBuffer();
~DrawBuffer();
void Begin(Draw::Pipeline *pipeline);
2018-12-18 10:10:53 +01:00
void Flush(bool set_blend_state = true);
2013-01-10 09:42:02 +01:00
// TODO: Enforce these. Now Init is autocalled and shutdown not called.
void Init(Draw::DrawContext *t3d, Draw::Pipeline *pipeline);
void Shutdown();
// So that callers can create appropriate pipelines.
Draw::InputLayout *CreateInputLayout(Draw::DrawContext *t3d);
2013-01-10 09:42:02 +01:00
int Count() const { return count_; }
void Rect(float x, float y, float w, float h, uint32_t color, int align = ALIGN_TOPLEFT);
void hLine(float x1, float y, float x2, uint32_t color);
void vLine(float x, float y1, float y2, uint32_t color);
2013-01-10 09:42:02 +01:00
void Line(ImageID atlas_image, float x1, float y1, float x2, float y2, float thickness, uint32_t color);
2014-02-27 01:22:47 +07:00
void RectOutline(float x, float y, float w, float h, uint32_t color, int align = ALIGN_TOPLEFT);
2014-02-27 01:22:47 +07:00
// NOTE: This one takes x2/y2 instead of w/h, better for gap-free graphics.
void RectVGradient(float x1, float y1, float x2, float y2, uint32_t colorTop, uint32_t colorBottom);
void RectVDarkFaded(float x, float y, float w, float h, uint32_t colorTop) {
RectVGradient(x, y, x + w, y + h, colorTop, darkenColor(colorTop));
2013-01-10 09:42:02 +01:00
}
void MultiVGradient(float x, float y, float w, float h, const GradientStop *stops, int numStops);
2013-01-10 09:42:02 +01:00
void RectCenter(float x, float y, float w, float h, uint32_t color) {
2013-01-10 09:42:02 +01:00
Rect(x - w/2, y - h/2, w, h, color);
}
void Rect(float x, float y, float w, float h, float u, float v, float uw, float uh, uint32_t color);
2013-01-10 09:42:02 +01:00
void V(float x, float y, float z, uint32_t color, float u, float v);
void V(float x, float y, uint32_t color, float u, float v) {
V(x, y, curZ_, color, u, v);
2013-01-10 09:42:02 +01:00
}
void Circle(float x, float y, float radius, float thickness, int segments, float startAngle, uint32_t color, float u_mul);
void FillCircle(float x, float y, float radius, int segments, uint32_t color);
2013-01-10 09:42:02 +01:00
// New drawing APIs
// Must call this before you use any functions with atlas_image etc.
void SetAtlas(const Atlas *_atlas) {
atlas = _atlas;
}
2013-05-03 00:21:39 +02:00
const Atlas *GetAtlas() const { return atlas; }
void SetFontAtlas(const Atlas *_atlas) {
fontAtlas_ = _atlas;
}
const Atlas *GetFontAtlas() const { return fontAtlas_; }
bool MeasureImage(ImageID atlas_image, float *w, float *h);
2013-08-20 00:34:54 +02:00
void DrawImage(ImageID atlas_image, float x, float y, float scale, Color color = COLOR(0xFFFFFF), int align = ALIGN_TOPLEFT);
// Good for stretching out a white image without edge artifacts that I'm getting on iOS.
void DrawImageCenterTexel(ImageID atlas_image, float x1, float y1, float x2, float y2, Color color = COLOR(0xFFFFFF));
2013-08-20 00:34:54 +02:00
void DrawImageStretch(ImageID atlas_image, float x1, float y1, float x2, float y2, Color color = COLOR(0xFFFFFF));
void DrawImageStretchVGradient(ImageID atlas_image, float x1, float y1, float x2, float y2, Color color1, Color color2);
void DrawImageStretch(ImageID atlas_image, const Bounds &bounds, Color color = COLOR(0xFFFFFF)) {
DrawImageStretch(atlas_image, bounds.x, bounds.y, bounds.x2(), bounds.y2(), color);
}
2013-08-20 00:34:54 +02:00
void DrawImageRotated(ImageID atlas_image, float x, float y, float scale, float angle, Color color = COLOR(0xFFFFFF), bool mirror_h = false); // Always centers
void DrawImageRotatedStretch(ImageID atlas_image, const Bounds &bounds, float scales[2], float angle, Color color = COLOR(0xFFFFFF), bool mirror_h = false);
2013-01-10 09:42:02 +01:00
void DrawTexRect(float x1, float y1, float x2, float y2, float u1, float v1, float u2, float v2, Color color);
void DrawTexRect(const Bounds &bounds, float u1, float v1, float u2, float v2, Color color) {
DrawTexRect(bounds.x, bounds.y, bounds.x2(), bounds.y2(), u1, v1, u2, v2, color);
}
2013-01-10 09:42:02 +01:00
// Results in 18 triangles. Kind of expensive for a button.
2013-08-20 00:34:54 +02:00
void DrawImage4Grid(ImageID atlas_image, float x1, float y1, float x2, float y2, Color color = COLOR(0xFFFFFF), float corner_scale = 1.0);
2013-01-10 09:42:02 +01:00
// This is only 6 triangles, much cheaper.
2013-08-20 00:34:54 +02:00
void DrawImage2GridH(ImageID atlas_image, float x1, float y1, float x2, Color color = COLOR(0xFFFFFF), float scale = 1.0);
2013-01-10 09:42:02 +01:00
void MeasureText(FontID font, const char *text, float *w, float *h);
// NOTE: Count is in plain chars not utf-8 chars!
void MeasureTextCount(FontID font, const char *text, int count, float *w, float *h);
void MeasureTextRect(FontID font, const char *text, int count, const Bounds &bounds, float *w, float *h, int align = 0);
void DrawTextRect(FontID font, const char *text, float x, float y, float w, float h, Color color = 0xFFFFFFFF, int align = 0);
void DrawText(FontID font, const char *text, float x, float y, Color color = 0xFFFFFFFF, int align = 0);
void DrawTextShadow(FontID font, const char *text, float x, float y, Color color = 0xFFFFFFFF, int align = 0);
2013-01-10 09:42:02 +01:00
void SetFontScale(float xs, float ys) {
fontscalex = xs;
fontscaley = ys;
}
static void DoAlign(int flags, float *x, float *y, float *w, float *h);
void PushDrawMatrix(const Lin::Matrix4x4 &m) {
drawMatrixStack_.push_back(drawMatrix_);
2014-08-17 12:17:59 +02:00
drawMatrix_ = m;
}
void PopDrawMatrix() {
drawMatrix_ = drawMatrixStack_.back();
drawMatrixStack_.pop_back();
}
Lin::Matrix4x4 GetDrawMatrix() {
return drawMatrix_;
}
void PushAlpha(float a) {
alphaStack_.push_back(alpha_);
alpha_ *= a;
}
void PopAlpha() {
alpha_ = alphaStack_.back();
alphaStack_.pop_back();
}
void SetCurZ(float curZ) {
curZ_ = curZ;
}
void SetTintSaturation(float tint, float saturation) {
tint_ = tint;
saturation_ = saturation;
}
2012-05-08 22:04:24 +02:00
private:
2013-01-10 09:42:02 +01:00
struct Vertex {
float x, y, z;
float u, v;
2014-08-17 12:17:59 +02:00
uint32_t rgba;
2013-01-10 09:42:02 +01:00
};
Lin::Matrix4x4 drawMatrix_;
std::vector<Lin::Matrix4x4> drawMatrixStack_;
float alpha_ = 1.0f;
std::vector<float> alphaStack_;
2014-08-17 12:17:59 +02:00
Draw::DrawContext *draw_ = nullptr;
Draw::Pipeline *pipeline_ = nullptr;
2013-03-30 19:23:02 +01:00
2013-01-10 09:42:02 +01:00
Vertex *verts_;
int count_ = 0;
const Atlas *atlas = nullptr;
const Atlas *fontAtlas_ = nullptr;
2013-01-10 09:42:02 +01:00
bool inited_ = false;
float fontscalex = 1.0f;
float fontscaley = 1.0f;
float tint_ = 0.0f;
float saturation_ = 1.0f;
float curZ_ = 0.0f;
2012-03-24 23:39:19 +01:00
};