2024-03-05 14:17:53 +08:00
|
|
|
|
|
|
|
#include "render_util.h"
|
2024-03-19 11:59:09 +08:00
|
|
|
#include "camera.h"
|
|
|
|
#include "render_pattern.h"
|
2024-03-05 14:17:53 +08:00
|
|
|
#include "easyx.h"
|
2024-03-19 11:59:09 +08:00
|
|
|
#include "types.h"
|
2024-03-05 14:17:53 +08:00
|
|
|
#include "util/vector.h"
|
2024-03-19 11:59:09 +08:00
|
|
|
#include "app.h"
|
2024-03-05 14:17:53 +08:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
2024-03-19 11:59:09 +08:00
|
|
|
#include <math.h>
|
|
|
|
#include <wingdi.h>
|
2024-03-05 14:17:53 +08:00
|
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
|
|
|
|
static vector_Vector *tbuf;
|
|
|
|
|
2024-03-25 21:10:40 +08:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
#define NCHAR char
|
|
|
|
#else
|
|
|
|
#define NCHAR wchar_t
|
|
|
|
#endif
|
|
|
|
|
2024-03-05 14:17:53 +08:00
|
|
|
void render_DrawText(int x, int y, const char *str) {
|
|
|
|
if (!tbuf)
|
2024-03-25 21:10:40 +08:00
|
|
|
tbuf = vector_Create(sizeof(NCHAR));
|
2024-03-05 14:17:53 +08:00
|
|
|
|
2024-03-25 21:10:40 +08:00
|
|
|
int cx = x, cy = y;
|
|
|
|
const NCHAR zero = 0;
|
2024-03-05 14:17:53 +08:00
|
|
|
|
|
|
|
vector_Clear(tbuf);
|
|
|
|
int len = strlen(str);
|
2024-03-05 14:26:39 +08:00
|
|
|
int i = 0;
|
2024-03-05 14:17:53 +08:00
|
|
|
while (i < len) {
|
|
|
|
if (str[i] == '\n') {
|
|
|
|
vector_Push(tbuf, &zero);
|
|
|
|
outtextxy(cx, cy, (LPCTSTR)vector_Data(tbuf));
|
|
|
|
|
|
|
|
cy += TEXTHEIGHT;
|
|
|
|
vector_Clear(tbuf);
|
2024-03-25 21:10:40 +08:00
|
|
|
} else {
|
|
|
|
NCHAR wc = str[i];
|
|
|
|
vector_Push(tbuf, &wc);
|
|
|
|
}
|
2024-03-05 14:17:53 +08:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vector_Size(tbuf) > 0) {
|
|
|
|
vector_Push(tbuf, &zero);
|
|
|
|
outtextxy(cx, cy, (LPCTSTR)vector_Data(tbuf));
|
|
|
|
vector_Clear(tbuf);
|
|
|
|
}
|
|
|
|
}
|
2024-03-19 11:59:09 +08:00
|
|
|
|
|
|
|
|
2024-03-25 14:59:00 +08:00
|
|
|
const FillMode render_ModeDefault = {
|
2024-03-19 11:59:09 +08:00
|
|
|
.rop2 = R2_COPYPEN,
|
|
|
|
.style = BS_SOLID,
|
|
|
|
.hatch = 0,
|
|
|
|
.rotate = {.microseconds = 0},
|
2024-03-19 15:14:23 +08:00
|
|
|
.dissolve = {.microseconds = 0},
|
2024-04-16 21:08:21 +08:00
|
|
|
.fadein = false,
|
|
|
|
.bg = 0,
|
|
|
|
.fg = 0xffffff};
|
2024-03-25 14:59:00 +08:00
|
|
|
const FillMode render_ModeInverse = {
|
|
|
|
.rop2 = R2_NOT,
|
|
|
|
.style = BS_SOLID,
|
|
|
|
.hatch = 0,
|
|
|
|
.rotate = {.microseconds = 0},
|
|
|
|
.dissolve = {.microseconds = 0},
|
2024-04-16 21:08:21 +08:00
|
|
|
.fadein = false,
|
|
|
|
.bg = 0,
|
|
|
|
.fg = 0xffffff};
|
2024-03-26 16:55:28 +08:00
|
|
|
extern const FillMode render_ModeRotate = {
|
|
|
|
.rop2 = R2_COPYPEN,
|
|
|
|
.style = BS_SOLID,
|
|
|
|
.hatch = 0,
|
|
|
|
.rotate = {.microseconds = 100000},
|
|
|
|
.dissolve = {.microseconds = 0},
|
2024-04-16 21:08:21 +08:00
|
|
|
.fadein = false,
|
|
|
|
.bg = 0,
|
|
|
|
.fg = 0xffffff};
|
2024-03-19 11:59:09 +08:00
|
|
|
|
|
|
|
|
|
|
|
void render_SetModes(FillMode mode, TimePoint since) {
|
|
|
|
if (mode.dissolve.microseconds != 0) {
|
|
|
|
// Dissolve mode
|
|
|
|
double progress = duration_Seconds(time_Since(since)) / duration_Seconds(mode.dissolve);
|
2024-03-19 15:14:23 +08:00
|
|
|
if (mode.fadein)
|
|
|
|
setfillstyle(render_DissolvePatternIn(progress)); // progress is capped into [0,1] in this func
|
|
|
|
else
|
|
|
|
setfillstyle(render_DissolvePatternOut(progress));
|
2024-03-19 11:59:09 +08:00
|
|
|
setrop2(R2_COPYPEN);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode.rotate.microseconds != 0) {
|
|
|
|
// Rotate mode
|
2024-03-25 21:10:40 +08:00
|
|
|
int steps = (int)round(duration_Seconds(time_Since(since)) / duration_Seconds(mode.rotate));
|
2024-03-19 11:59:09 +08:00
|
|
|
|
|
|
|
static const long hatches[] = {HS_HORIZONTAL, HS_FDIAGONAL, HS_VERTICAL, HS_BDIAGONAL};
|
|
|
|
setfillstyle(BS_HATCHED, hatches[steps % 4], NULL);
|
|
|
|
setrop2(R2_COPYPEN);
|
2024-04-16 21:08:21 +08:00
|
|
|
setfillcolor(0xffffff);
|
|
|
|
setbkcolor(0);
|
2024-03-19 11:59:09 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Normal mode
|
|
|
|
setfillstyle(mode.style, mode.hatch, NULL);
|
|
|
|
setrop2(mode.rop2);
|
2024-04-16 21:08:21 +08:00
|
|
|
setlinecolor(mode.fg);
|
|
|
|
setfillcolor(mode.fg);
|
|
|
|
setbkcolor(mode.bg);
|
2024-03-19 11:59:09 +08:00
|
|
|
}
|
|
|
|
|
2024-03-19 15:14:23 +08:00
|
|
|
void render_FillScreen() {
|
2024-03-19 12:01:36 +08:00
|
|
|
solidrectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
2024-03-19 11:59:09 +08:00
|
|
|
}
|
|
|
|
|
2024-03-19 15:14:23 +08:00
|
|
|
void render_FillRectW(App *app, Box2 rect) {
|
2024-03-19 11:59:09 +08:00
|
|
|
if (app->camera)
|
|
|
|
rect = camera_TransformBox2(app->camera, rect);
|
|
|
|
else
|
|
|
|
fprintf(stderr, "[WARN][render_FillRectW] called without an active camera system\n");
|
2024-03-19 12:01:36 +08:00
|
|
|
solidrectangle(
|
2024-03-19 11:59:09 +08:00
|
|
|
(int)round(rect.lefttop.x),
|
|
|
|
(int)round(rect.lefttop.y),
|
|
|
|
(int)round(rect.lefttop.x + rect.size.x),
|
|
|
|
(int)round(rect.lefttop.y + rect.size.y));
|
|
|
|
}
|
|
|
|
|
2024-03-19 15:14:23 +08:00
|
|
|
void render_FillCircleW(App *app, Vec2 center, double radius) {
|
2024-03-19 11:59:09 +08:00
|
|
|
if (app->camera) {
|
|
|
|
center = camera_TransformVec2(app->camera, center);
|
|
|
|
radius = camera_TransformSize(app->camera, vec2(radius, 0)).x; // TODO non-aspect scaling
|
|
|
|
} else
|
|
|
|
fprintf(stderr, "[WARN][render_FillCircleW] called without an active camera system\n");
|
2024-03-19 12:01:36 +08:00
|
|
|
solidcircle(
|
2024-03-19 11:59:09 +08:00
|
|
|
(int)round(center.x),
|
|
|
|
(int)round(center.y),
|
|
|
|
(int)round(radius));
|
|
|
|
}
|
2024-03-05 14:17:53 +08:00
|
|
|
}
|