From: yu.dongliang <18588496441@163.com>
Date: Fri, 20 Sep 2024 12:07:20 +0000 (+0800)
Subject: support HTML
X-Git-Url: http://baseworks.info/?a=commitdiff_plain;h=b63e932410afc112024c4833b034c68508ad1020;p=abc.git
support HTML
---
diff --git a/examples/img.html b/examples/img.html
new file mode 100644
index 0000000..47cfb78
--- /dev/null
+++ b/examples/img.html
@@ -0,0 +1,9 @@
+
+
+
+å¾ç
+
+
+
+
+
diff --git a/examples/img.png b/examples/img.png
new file mode 100644
index 0000000..a3a560b
Binary files /dev/null and b/examples/img.png differ
diff --git a/ffmpeg/Makefile b/ffmpeg/Makefile
new file mode 100644
index 0000000..1b8f12a
--- /dev/null
+++ b/ffmpeg/Makefile
@@ -0,0 +1,17 @@
+CFILES += ../util/scf_string.c
+
+CFILES += main.c
+CFILES += abc_ffmpeg_img.c
+
+CFLAGS += -g
+CFLAGS += -I../util
+
+LDFLAGS += -lavformat -lavcodec -lavfilter -lavutil
+LDFLAGS += -lcairo
+LDFLAGS += -ldl
+
+all:
+ gcc $(CFLAGS) $(CFILES) $(LDFLAGS)
+
+clean:
+ rm *.o
diff --git a/ffmpeg/abc_ffmpeg.h b/ffmpeg/abc_ffmpeg.h
new file mode 100644
index 0000000..60c8620
--- /dev/null
+++ b/ffmpeg/abc_ffmpeg.h
@@ -0,0 +1,34 @@
+#ifndef ABC_FFMPEG_H
+#define ABC_FFMPEG_H
+
+#include"scf_def.h"
+
+#include "libavformat/avformat.h"
+#include "libavcodec/avcodec.h"
+#include "libavutil/avutil.h"
+#include "libavutil/opt.h"
+#include "libavfilter/avfilter.h"
+#include "libavfilter/buffersrc.h"
+#include "libavfilter/buffersink.h"
+
+typedef struct {
+ AVFormatContext* fmt_ctx;
+ AVCodecContext* dec_ctx;
+ int video_index;
+
+ AVFilterContext* buffersrc_ctx;
+ AVFilterContext* buffersink_ctx;
+ AVFilterGraph* filter_graph;
+
+ int width;
+ int height;
+} abc_img_t;
+
+
+int abc_img_open (abc_img_t** pimg, const char* path);
+void abc_img_close(abc_img_t* img);
+
+// ffmpeg BGRA == cario ARGB, Blue in byte[0].
+int abc_img_read (abc_img_t* img, uint8_t* bgra, int size);
+
+#endif
diff --git a/ffmpeg/abc_ffmpeg_img.c b/ffmpeg/abc_ffmpeg_img.c
new file mode 100644
index 0000000..a9bf794
--- /dev/null
+++ b/ffmpeg/abc_ffmpeg_img.c
@@ -0,0 +1,266 @@
+#include "abc_ffmpeg.h"
+
+static int __ffmpeg_init(abc_img_t* img, const char* filename)
+{
+ int ret = avformat_open_input(&img->fmt_ctx, filename, NULL, NULL);
+ if (ret < 0) {
+ scf_loge("avformat_open_input, %s\n", av_err2str(ret));
+ return ret;
+ }
+
+ ret = avformat_find_stream_info(img->fmt_ctx, NULL);
+ if (ret < 0) {
+ scf_loge("avformat_find_stream_info, %s\n", av_err2str(ret));
+ return ret;
+ }
+
+ AVStream* s = NULL;
+ AVCodec* c = NULL;
+
+ int i;
+ for (i = 0; i < img->fmt_ctx->nb_streams; i++) {
+ s = img->fmt_ctx->streams[i];
+
+ if (AVMEDIA_TYPE_VIDEO == s->codecpar->codec_type) {
+ img->video_index = i;
+ break;
+ }
+ }
+
+ if (i == img->fmt_ctx->nb_streams) {
+ scf_loge("video stream not found\n");
+ return -1;
+ }
+
+ c = avcodec_find_decoder(s->codecpar->codec_id);
+ if (!c) {
+ scf_loge("decoder not found, codec_id: %d\n", s->codecpar->codec_id);
+ return -EINVAL;
+ }
+
+ img->dec_ctx = avcodec_alloc_context3(c);
+ if (!img->dec_ctx) {
+ scf_loge("avcodec_alloc_context3() failed\n");
+ return -ENOMEM;
+ }
+
+ ret = avcodec_parameters_to_context(img->dec_ctx, s->codecpar);
+ if (ret < 0) {
+ scf_loge("avcodec_parameters_to_context, %s\n", av_err2str(ret));
+ return ret;
+ }
+
+ ret = avcodec_open2(img->dec_ctx, c, NULL);
+ if (ret < 0) {
+ scf_loge("avcodec_parameters_to_context, %s\n", av_err2str(ret));
+ return ret;
+ }
+
+ img->width = img->dec_ctx->width;
+ img->height = img->dec_ctx->height;
+ return 0;
+}
+
+static int __init_filters(abc_img_t* img, const char *filters_desc)
+{
+ char args[512];
+ int ret = 0;
+
+ const AVFilter *buffersrc = avfilter_get_by_name("buffer");
+ const AVFilter *buffersink = avfilter_get_by_name("buffersink");
+
+ AVFilterInOut *outputs = avfilter_inout_alloc();
+ AVFilterInOut *inputs = avfilter_inout_alloc();
+
+ AVCodecContext* dec_ctx = img->dec_ctx;
+ AVStream* s = img->fmt_ctx->streams[img->video_index];
+
+ enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE};
+
+ img->filter_graph = avfilter_graph_alloc();
+ if (!outputs || !inputs || !img->filter_graph) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ snprintf(args, sizeof(args),
+ "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
+ dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
+ s->time_base.num, s->time_base.den,
+ dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);
+
+ ret = avfilter_graph_create_filter(&img->buffersrc_ctx, buffersrc, "in", args, NULL, img->filter_graph);
+ if (ret < 0)
+ goto end;
+
+ ret = avfilter_graph_create_filter(&img->buffersink_ctx, buffersink, "out", NULL, NULL, img->filter_graph);
+ if (ret < 0)
+ goto end;
+
+ ret = av_opt_set_int_list(img->buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0)
+ goto end;
+
+ outputs->name = av_strdup("in");
+ outputs->filter_ctx = img->buffersrc_ctx;
+ outputs->pad_idx = 0;
+ outputs->next = NULL;
+
+ inputs->name = av_strdup("out");
+ inputs->filter_ctx = img->buffersink_ctx;
+ inputs->pad_idx = 0;
+ inputs->next = NULL;
+
+ if ((ret = avfilter_graph_parse_ptr(img->filter_graph, filters_desc, &inputs, &outputs, NULL)) < 0)
+ goto end;
+
+ if ((ret = avfilter_graph_config(img->filter_graph, NULL)) < 0)
+ goto end;
+
+end:
+ avfilter_inout_free(&inputs);
+ avfilter_inout_free(&outputs);
+ return ret;
+}
+
+int abc_img_open(abc_img_t** pimg, const char* path)
+{
+ if (!pimg || !path)
+ return -EINVAL;
+
+ abc_img_t* img = calloc(1, sizeof(abc_img_t));
+ if (!img)
+ return -ENOMEM;
+
+ int ret = __ffmpeg_init(img, path);
+ if (ret < 0) {
+ abc_img_close(img);
+ return ret;
+ }
+
+ *pimg = img;
+ return 0;
+}
+
+void abc_img_close(abc_img_t* img)
+{
+ if (img) {
+ avcodec_free_context(&img->dec_ctx);
+ avformat_close_input(&img->fmt_ctx);
+
+ if (img->filter_graph)
+ avfilter_graph_free(&img->filter_graph);
+
+ free(img);
+ }
+}
+
+int abc_img_read(abc_img_t* img, uint8_t* bgra, int size)
+{
+ if (!img || !bgra || size < img->width * img->height * 4)
+ return -EINVAL;
+
+ char filters_desc[256];
+ snprintf(filters_desc, sizeof(filters_desc), "scale=%dx%d", img->width, img->height);
+
+ int ret = __init_filters(img, filters_desc);
+ if (ret < 0) {
+ scf_loge("ffmpeg_init error\n");
+ return ret;
+ }
+
+ AVFrame* frame = av_frame_alloc();
+ if (!frame)
+ return -ENOMEM;
+
+ AVFrame* frame2 = av_frame_alloc();
+ if (!frame2) {
+ av_frame_free(&frame);
+ return -ENOMEM;
+ }
+
+ AVPacket* pkt = av_packet_alloc();
+ if (!pkt) {
+ av_frame_free(&frame);
+ av_frame_free(&frame2);
+ return -ENOMEM;
+ }
+
+ int key_frame = 0;
+
+ while (1) {
+ ret = av_read_frame(img->fmt_ctx, pkt);
+ if (ret < 0) {
+ scf_loge("av_read_frame, %s\n", av_err2str(ret));
+ goto end;
+ }
+
+ if (pkt->stream_index != img->video_index) {
+ av_packet_unref(pkt);
+ continue;
+ }
+
+ if (pkt->flags & AV_PKT_FLAG_KEY)
+ key_frame++;
+
+ if (key_frame > 0)
+ break;
+
+ av_packet_unref(pkt);
+ }
+
+ ret = avcodec_send_packet(img->dec_ctx, pkt);
+ if (ret < 0) {
+ scf_loge("avcodec_send_packet, %s\n", av_err2str(ret));
+ goto end;
+ }
+
+ while (ret >= 0) {
+ ret = avcodec_receive_frame(img->dec_ctx, frame);
+
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ break;
+ else if (ret < 0) {
+ scf_loge("avcodec_receive_frame, %s\n", av_err2str(ret));
+ goto end;
+ }
+
+ frame->pts = frame->best_effort_timestamp;
+
+ ret = av_buffersrc_add_frame_flags(img->buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);
+ if (ret < 0) {
+ scf_loge("av_buffersrc_add_frame_flags, %s\n", av_err2str(ret));
+ goto end;
+ }
+
+ while (1) {
+ ret = av_buffersink_get_frame(img->buffersink_ctx, frame2);
+
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ break;
+ else if (ret < 0) {
+ scf_loge("av_buffersink_get_frame, %s\n", av_err2str(ret));
+ goto end;
+ }
+
+ assert(img->width == frame2->width);
+ assert(img->height == frame2->height);
+
+ scf_logi("frame2->linesize[0]: %d\n", frame2->linesize[0]);
+
+ int i;
+ for (i = 0; i < frame2->height; i++)
+ memcpy(bgra + i * frame2->width * 4, frame2->data[0] + i * frame2->linesize[0], frame2->width * 4);
+
+ av_frame_unref(frame2);
+ }
+ av_frame_unref(frame);
+ }
+
+ ret = 0;
+end:
+ av_packet_free(&pkt);
+ av_frame_free(&frame);
+ av_frame_free(&frame2);
+ return ret;
+}
diff --git a/ffmpeg/main.c b/ffmpeg/main.c
new file mode 100644
index 0000000..92093b4
--- /dev/null
+++ b/ffmpeg/main.c
@@ -0,0 +1,49 @@
+#include
+#include"abc_ffmpeg.h"
+
+int main(int argc, char* argv[])
+{
+ abc_img_t* img = NULL;
+
+ if (argc < 2) {
+ scf_loge("\n");
+ return -1;
+ }
+
+ if (abc_img_open(&img, argv[1]) < 0) {
+ scf_loge("\n");
+ return -1;
+ }
+
+ scf_logi("img->width: %d, img->height: %d\n", img->width, img->height);
+
+ int size = img->width * img->height * 4;
+
+ uint8_t* rgba = calloc(1, size);
+ if (!rgba) {
+ scf_loge("\n");
+ return -1;
+ }
+
+ if (abc_img_read(img, rgba, size) < 0) {
+ scf_loge("\n");
+ return -1;
+ }
+
+
+ cairo_surface_t* surface;
+ cairo_t* cr;
+
+ surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, img->width, img->height, img->width * 4);
+ cr = cairo_create(surface);
+
+ cairo_surface_write_to_png(surface, "1.png");
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+
+ printf("\n");
+
+ scf_logi("main ok\n");
+ return 0;
+}
diff --git a/html/abc_html.c b/html/abc_html.c
index 1c4791e..a49508b 100644
--- a/html/abc_html.c
+++ b/html/abc_html.c
@@ -21,6 +21,36 @@ static html_attr_t h1_attrs[] =
{"font-size", "32", ABC_HTML_ATTR_FONT_SIZE},
};
+static html_attr_t h2_attrs[] =
+{
+ {"font", "Liberation Serif", ABC_HTML_ATTR_FONT},
+ {"font-size", "28", ABC_HTML_ATTR_FONT_SIZE},
+};
+
+static html_attr_t h3_attrs[] =
+{
+ {"font", "Liberation Serif", ABC_HTML_ATTR_FONT},
+ {"font-size", "24", ABC_HTML_ATTR_FONT_SIZE},
+};
+
+static html_attr_t h4_attrs[] =
+{
+ {"font", "Liberation Serif", ABC_HTML_ATTR_FONT},
+ {"font-size", "20", ABC_HTML_ATTR_FONT_SIZE},
+};
+
+static html_attr_t h5_attrs[] =
+{
+ {"font", "Liberation Serif", ABC_HTML_ATTR_FONT},
+ {"font-size", "16", ABC_HTML_ATTR_FONT_SIZE},
+};
+
+static html_attr_t h6_attrs[] =
+{
+ {"font", "Liberation Serif", ABC_HTML_ATTR_FONT},
+ {"font-size", "12", ABC_HTML_ATTR_FONT_SIZE},
+};
+
static html_attr_t a_attrs[] =
{
{"href", "", ABC_HTML_ATTR_HREF},
@@ -29,6 +59,13 @@ static html_attr_t a_attrs[] =
{"font-color", "blue", ABC_HTML_ATTR_FONT_COLOR},
};
+static html_attr_t img_attrs[] =
+{
+ {"src", "", ABC_HTML_ATTR_SRC},
+ {"width", "100", ABC_HTML_ATTR_WIDTH},
+ {"height", "100", ABC_HTML_ATTR_HEIGHT},
+};
+
static html_label_t html_labels[] =
{
{"html", ABC_HTML, 0, NULL},
@@ -39,7 +76,14 @@ static html_label_t html_labels[] =
{"div", ABC_HTML_DIV, 0, NULL},
{"h1", ABC_HTML_H1, sizeof(h1_attrs) / sizeof(h1_attrs[0]), h1_attrs},
- {"a", ABC_HTML_A, sizeof(a_attrs) / sizeof(a_attrs[0]), a_attrs},
+ {"h2", ABC_HTML_H2, sizeof(h2_attrs) / sizeof(h2_attrs[0]), h2_attrs},
+ {"h3", ABC_HTML_H3, sizeof(h3_attrs) / sizeof(h3_attrs[0]), h3_attrs},
+ {"h4", ABC_HTML_H4, sizeof(h4_attrs) / sizeof(h4_attrs[0]), h4_attrs},
+ {"h5", ABC_HTML_H5, sizeof(h5_attrs) / sizeof(h5_attrs[0]), h5_attrs},
+ {"h6", ABC_HTML_H6, sizeof(h6_attrs) / sizeof(h6_attrs[0]), h6_attrs},
+
+ {"a", ABC_HTML_A, sizeof(a_attrs) / sizeof(a_attrs[0]), a_attrs},
+ {"img", ABC_HTML_IMG, sizeof(img_attrs) / sizeof(img_attrs[0]), img_attrs},
};
static int __html_parse_obj(abc_html_t* html, abc_char_t* c);
@@ -308,7 +352,7 @@ static int __html_parse_value(abc_html_t* html, abc_obj_t* attr)
scf_string_free(attr->value);
attr->value = value;
- return '>' == tmp;
+ return tmp;
}
static int __html_parse_attr2(abc_html_t* html, abc_obj_t* obj, const html_attr_t* attrs, int n_attrs)
@@ -332,13 +376,19 @@ static int __html_parse_attr2(abc_html_t* html, abc_obj_t* obj, const html_attr_
if ('=' == c->c)
break;
+ if ('/' == c->c) {
+ free(c);
+ scf_string_free(key);
+ return '/';
+ }
+
if ('_' == c->c
|| '-' == c->c
|| ('a' <= c->c && 'z' >= c->c))
scf_string_cat_cstr_len(key, c->utf8, c->len);
else {
- scf_loge("invalid char in HTML attribute, file: %s, line: %d\n",
- html->file->data, html->n_lines);
+ scf_loge("invalid char '%c' in HTML attribute, file: %s, line: %d\n",
+ c->c, html->file->data, html->n_lines);
free(c);
scf_string_free(key);
return -1;
@@ -389,13 +439,16 @@ static int __html_parse_attr(abc_html_t* html, abc_obj_t* obj, const html_attr_t
{
int ret = 0;
- while (!ret) {
+ while (1) {
ret = __html_parse_attr2(html, obj, attrs, n_attrs);
if (ret < 0)
return ret;
+
+ if ('>' == ret || '/' == ret)
+ break;
}
- return 0;
+ return ret;
}
static int __html_parse_obj(abc_html_t* html, abc_char_t* c)
@@ -464,6 +517,7 @@ static int __html_parse_obj(abc_html_t* html, abc_char_t* c)
return ret;
}
+ ret = 0;
if (' ' == tmp) {
ret = __html_parse_attr(html, obj, label->attrs, label->n_attrs);
if (ret < 0) {
@@ -486,7 +540,25 @@ static int __html_parse_obj(abc_html_t* html, abc_char_t* c)
html->current = obj;
}
- ret = __html_parse_text(html, obj);
+ if ('/' == ret) {
+ c = __html_pop_char(html);
+ if (!c) {
+ scf_loge("\n");
+ return -1;
+ }
+
+ int tmp = c->c;
+
+ free(c);
+ c = NULL;
+
+ if ('>' != tmp) {
+ scf_loge("HTML label '%s' not closed, in file: %s, line: %d\n",
+ obj->key->data, html->file->data, html->n_lines);
+ return -1;
+ }
+ } else
+ ret = __html_parse_text(html, obj);
html->current = obj->parent;
return ret;
diff --git a/html/abc_obj.h b/html/abc_obj.h
index 431e6f4..f1babf8 100644
--- a/html/abc_obj.h
+++ b/html/abc_obj.h
@@ -15,18 +15,34 @@ enum abc_objs
// 4
ABC_HTML_DIV,
+
+ // 5
ABC_HTML_H1,
+ ABC_HTML_H2,
+ ABC_HTML_H3,
+ ABC_HTML_H4,
+ ABC_HTML_H5,
+ ABC_HTML_H6,
+
+ // 11
ABC_HTML_A,
ABC_HTML_A_HREF,
+ // 13
+ ABC_HTML_IMG,
+
ABC_HTML_NB, // total HTML objects
ABC_HTML_ATTR_ID,
ABC_HTML_ATTR_HREF,
+ ABC_HTML_ATTR_SRC,
ABC_HTML_ATTR_FONT,
ABC_HTML_ATTR_FONT_SIZE,
ABC_HTML_ATTR_FONT_COLOR,
+
+ ABC_HTML_ATTR_WIDTH,
+ ABC_HTML_ATTR_HEIGHT,
};
struct abc_obj_s
diff --git a/ui/Makefile b/ui/Makefile
index b06f22c..4dc7d04 100644
--- a/ui/Makefile
+++ b/ui/Makefile
@@ -8,6 +8,7 @@ CFILES += abc_layout_body.c
CFILES += abc_layout_div.c
CFILES += abc_layout_h1.c
CFILES += abc_layout_a.c
+CFILES += abc_layout_img.c
CFILES += abc_render.c
CFILES += abc_render_html.c
@@ -18,16 +19,20 @@ CFILES += abc_render_div.c
CFILES += abc_render_h1.c
CFILES += abc_render_a.c
CFILES += abc_render_a_href.c
+CFILES += abc_render_img.c
CFILES += ../html/abc_html.c
CFILES += ../html/abc_html_util.c
CFILES += ../html/abc_obj.c
+CFILES += ../ffmpeg/abc_ffmpeg_img.c
+
CFILES += ../util/scf_string.c
CFLAGS += -g -O3
CFLAGS += -I./
CFLAGS += -I../html
+CFLAGS += -I../ffmpeg
CFLAGS += -I../util
CFLAGS += `pkg-config --cflags gtk+-3.0`
diff --git a/ui/abc.h b/ui/abc.h
index 347e88b..02ac07e 100644
--- a/ui/abc.h
+++ b/ui/abc.h
@@ -72,4 +72,6 @@ int __init_texture(GLuint* ptex, GLenum format, int w, int h, uint8_t* data);
int __init_program(GLuint* pprog, const char* vert_shader, const char* frag_shader);
+int __init_buffers(GLuint* vao, GLuint buffers[2]);
+
#endif
diff --git a/ui/abc_layout.c b/ui/abc_layout.c
index 3ebf72c..b205320 100644
--- a/ui/abc_layout.c
+++ b/ui/abc_layout.c
@@ -8,6 +8,7 @@ int abc_layout_body (abc_layout_t* layout, abc_obj_t* root, int width, int heigh
int abc_layout_div (abc_layout_t* layout, abc_obj_t* root, int width, int height);
int abc_layout_h1 (abc_layout_t* layout, abc_obj_t* root, int width, int height);
int abc_layout_a (abc_layout_t* layout, abc_obj_t* root, int width, int height);
+int abc_layout_img (abc_layout_t* layout, abc_obj_t* root, int width, int height);
static abc_layout_pt abc_layouts[ABC_HTML_NB] =
{
@@ -18,8 +19,19 @@ static abc_layout_pt abc_layouts[ABC_HTML_NB] =
// 4
abc_layout_div,
+
+ abc_layout_h1,
+ abc_layout_h1,
+ abc_layout_h1,
abc_layout_h1,
+ abc_layout_h1,
+ abc_layout_h1,
+
+ // 11
abc_layout_a,
+ NULL,
+
+ abc_layout_img,
};
int abc_layout_obj(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
diff --git a/ui/abc_layout_img.c b/ui/abc_layout_img.c
new file mode 100644
index 0000000..5744271
--- /dev/null
+++ b/ui/abc_layout_img.c
@@ -0,0 +1,33 @@
+#include"abc.h"
+
+int abc_layout_img(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
+{
+ scf_list_t* l;
+ abc_obj_t* attr;
+
+ for (l = scf_list_head(&obj->attrs); l != scf_list_sentinel(&obj->attrs); l = scf_list_next(l)) {
+ attr = scf_list_data(l, abc_obj_t, list);
+
+ switch (attr->type) {
+
+ case ABC_HTML_ATTR_WIDTH:
+ obj->w = atoi(attr->value->data);
+ break;
+
+ case ABC_HTML_ATTR_HEIGHT:
+ obj->h = atoi(attr->value->data);
+ break;
+ default:
+ break;
+ };
+ }
+
+ obj->x = 4;
+ obj->y = 4;
+
+ obj->w = (obj->w + 3) & ~0x3;
+ obj->h = (obj->h + 3) & ~0x3;
+
+ scf_logd("%s, w: %d, h: %d\n", obj->text->data, obj->w, obj->h);
+ return 0;
+}
diff --git a/ui/abc_render.c b/ui/abc_render.c
index d97b6c2..a1485ef 100644
--- a/ui/abc_render.c
+++ b/ui/abc_render.c
@@ -9,6 +9,7 @@ extern abc_render_t abc_render_div;
extern abc_render_t abc_render_h1;
extern abc_render_t abc_render_a;
extern abc_render_t abc_render_a_href;
+extern abc_render_t abc_render_img;
static abc_render_t* abc_renders[ABC_HTML_NB] =
{
@@ -19,9 +20,19 @@ static abc_render_t* abc_renders[ABC_HTML_NB] =
// 4
&abc_render_div,
+
+ &abc_render_h1,
+ &abc_render_h1,
+ &abc_render_h1,
&abc_render_h1,
+ &abc_render_h1,
+ &abc_render_h1,
+
+ // 11
&abc_render_a,
&abc_render_a_href,
+
+ &abc_render_img,
};
int abc_renders_fini()
@@ -160,6 +171,29 @@ int __init_texture(GLuint* ptex, GLenum format, int w, int h, uint8_t* data)
return 0;
}
+int __init_buffers(GLuint* vao, GLuint buffers[2])
+{
+ glGenBuffers(2, buffers);
+ glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW);
+
+ glGenVertexArrays(1, vao);
+ glBindVertexArray(*vao);
+
+ glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+ glBindVertexArray(0);
+ return 0;
+}
+
int __init_program(GLuint* pprog, const char* vert_shader, const char* frag_shader)
{
GLint status = 0;
diff --git a/ui/abc_render_a.c b/ui/abc_render_a.c
index 02b37ba..a5eef25 100644
--- a/ui/abc_render_a.c
+++ b/ui/abc_render_a.c
@@ -32,31 +32,6 @@ static GLuint texture_rgba = 0;
static GLuint uniform_mvp;
static GLuint uniform_rgba;
-static int __width = 0;
-static int __height = 0;
-
-static int __init_buffers(GLuint* vao, GLuint buffers[2])
-{
- glGenBuffers(2, buffers);
- glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW);
-
- glGenVertexArrays(1, vao);
- glBindVertexArray(*vao);
-
- glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
- glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
- glBindVertexArray(0);
- return 0;
-}
static int _render_fini_a(abc_render_t* render)
{
@@ -81,11 +56,11 @@ static int _render_draw_a(abc_render_t* render, abc_obj_t* obj, int width, int h
scf_list_t* l;
abc_obj_t* attr;
- uint8_t* rgba = calloc(1, obj->w * obj->h * 4);
- if (!rgba)
+ uint8_t* bgra = calloc(1, obj->w * obj->h * 4);
+ if (!bgra)
return -ENOMEM;
- surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
+ surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
cr = cairo_create(surface);
cairo_set_line_width(cr, 1);
@@ -163,7 +138,7 @@ static int _render_draw_a(abc_render_t* render, abc_obj_t* obj, int width, int h
// board
glActiveTexture(GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, texture_rgba);
- glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
+ glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
glUniform1i(uniform_rgba, 0);
// draw
@@ -177,7 +152,7 @@ static int _render_draw_a(abc_render_t* render, abc_obj_t* obj, int width, int h
glBindVertexArray(0);
glUseProgram(0);
- free(rgba);
+ free(bgra);
return 0;
}
diff --git a/ui/abc_render_a_href.c b/ui/abc_render_a_href.c
index 96365c0..4eaddf1 100644
--- a/ui/abc_render_a_href.c
+++ b/ui/abc_render_a_href.c
@@ -32,31 +32,6 @@ static GLuint texture_rgba = 0;
static GLuint uniform_mvp;
static GLuint uniform_rgba;
-static int __width = 0;
-static int __height = 0;
-
-static int __init_buffers(GLuint* vao, GLuint buffers[2])
-{
- glGenBuffers(2, buffers);
- glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW);
-
- glGenVertexArrays(1, vao);
- glBindVertexArray(*vao);
-
- glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
- glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
- glBindVertexArray(0);
- return 0;
-}
static int _render_fini_a_href(abc_render_t* render)
{
@@ -81,11 +56,11 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width,
scf_list_t* l;
abc_obj_t* attr;
- uint8_t* rgba = malloc(width * 32 * 4);
- if (!rgba)
+ uint8_t* bgra = malloc(width * 32 * 4);
+ if (!bgra)
return -ENOMEM;
- surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, width, 32, width * 4);
+ surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, width, 32, width * 4);
cr = cairo_create(surface);
cairo_select_font_face(cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
@@ -116,23 +91,23 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width,
if (l == scf_list_sentinel(&obj->attrs)) {
scf_loge("hyper link '%s' not found a URL\n", obj->text->data);
- free(rgba);
- rgba = NULL;
+ free(bgra);
+ bgra = NULL;
return -EINVAL;
}
scf_logd("extents: x_bearing: %f, width: %f, y_bearing: %f, height: %f\n",
extents.x_bearing, extents.width, extents.y_bearing, extents.height);
- void* p = realloc(rgba, w * h * 4);
+ void* p = realloc(bgra, w * h * 4);
if (!p) {
- free(rgba);
- rgba = NULL;
+ free(bgra);
+ bgra = NULL;
return -ENOMEM;
}
- rgba = p;
+ bgra = p;
- surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, w, h, w * 4);
+ surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, w, h, w * 4);
cr = cairo_create(surface);
cairo_set_line_width(cr, 1);
@@ -188,7 +163,7 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width,
// board
glActiveTexture(GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, texture_rgba);
- glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
+ glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
glUniform1i(uniform_rgba, 0);
// draw
@@ -202,7 +177,7 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width,
glBindVertexArray(0);
glUseProgram(0);
- free(rgba);
+ free(bgra);
return 0;
}
diff --git a/ui/abc_render_h1.c b/ui/abc_render_h1.c
index 8a94b5c..db72fc2 100644
--- a/ui/abc_render_h1.c
+++ b/ui/abc_render_h1.c
@@ -32,31 +32,6 @@ static GLuint texture_rgba = 0;
static GLuint uniform_mvp;
static GLuint uniform_rgba;
-static int __width = 0;
-static int __height = 0;
-
-static int __init_buffers(GLuint* vao, GLuint buffers[2])
-{
- glGenBuffers(2, buffers);
- glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW);
-
- glGenVertexArrays(1, vao);
- glBindVertexArray(*vao);
-
- glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
- glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
- glBindVertexArray(0);
- return 0;
-}
static int _render_fini_h1(abc_render_t* render)
{
@@ -81,11 +56,11 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int
scf_list_t* l;
abc_obj_t* attr;
- uint8_t* rgba = calloc(1, obj->w * obj->h * 4);
- if (!rgba)
+ uint8_t* bgra = calloc(1, obj->w * obj->h * 4);
+ if (!bgra)
return -ENOMEM;
- surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
+ surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
cr = cairo_create(surface);
cairo_set_line_width(cr, 1);
@@ -152,7 +127,7 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int
// board
glActiveTexture(GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, texture_rgba);
- glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
+ glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
glUniform1i(uniform_rgba, 0);
// draw
@@ -166,7 +141,7 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int
glBindVertexArray(0);
glUseProgram(0);
- free(rgba);
+ free(bgra);
return 0;
}
diff --git a/ui/abc_render_img.c b/ui/abc_render_img.c
new file mode 100644
index 0000000..5e9feb7
--- /dev/null
+++ b/ui/abc_render_img.c
@@ -0,0 +1,140 @@
+#include"abc.h"
+#include"abc_ffmpeg.h"
+
+static const char* vert_shader =
+ "#version 330 core\n"
+ "layout(location = 0) in vec4 position; \n"
+ "layout(location = 1) in vec2 a_texCoord; \n"
+ "out vec2 v_texCoord; \n"
+ "uniform mat4 mvp; \n"
+ "void main() { \n"
+ "gl_Position = mvp * position; \n"
+ "v_texCoord = a_texCoord; \n"
+ "} \n";
+
+static const char* frag_shader =
+ "#version 330 core\n"
+ "in vec2 v_texCoord; \n"
+ "out vec4 outputColor; \n"
+ "uniform sampler2D tex_rgba; \n"
+ "void main() { \n"
+ " vec2 xy = v_texCoord; \n"
+ " vec4 v = texture2D(tex_rgba, xy).rgba; \n"
+ " outputColor = vec4(v.b, v.g, v.r, 1.0); \n"
+ "} \n";
+
+
+static GLuint program = 0;
+
+static GLuint vao = 0;
+static GLuint buffers[2] = {0};
+static GLuint texture_rgba = 0;
+
+static GLuint uniform_mvp;
+static GLuint uniform_rgba;
+
+
+static int _render_fini_img(abc_render_t* render)
+{
+ return 0;
+}
+
+static int _render_draw_img(abc_render_t* render, abc_obj_t* obj, int width, int height)
+{
+ scf_list_t* l;
+ abc_obj_t* attr;
+ abc_img_t* img = NULL;
+
+ for (l = scf_list_head(&obj->attrs); l != scf_list_sentinel(&obj->attrs); l = scf_list_next(l)) {
+ attr = scf_list_data(l, abc_obj_t, list);
+
+ if (ABC_HTML_ATTR_SRC == attr->type)
+ break;
+ }
+
+ if (l == scf_list_sentinel(&obj->attrs)) {
+ scf_loge("src image of '%s' not found\n", obj->key->data);
+ return -1;
+ }
+
+ int ret = abc_img_open(&img, attr->value->data);
+ if (ret < 0)
+ return ret;
+
+ uint8_t* bgra = calloc(1, img->width * img->height * 4);
+ if (!bgra) {
+ abc_img_close(img);
+ return -ENOMEM;
+ }
+
+ ret = abc_img_read(img, bgra, img->width * img->height * 4);
+ if (ret < 0) {
+ abc_img_close(img);
+ free(bgra);
+ return ret;
+ }
+
+ if (0 == program)
+ __init_program(&program, vert_shader, frag_shader);
+
+ if (0 == vao)
+ __init_buffers(&vao, buffers);
+
+ if (0 == texture_rgba)
+ __init_texture(&texture_rgba, GL_RGBA, img->width, img->height, NULL);
+
+ float mvp[16];
+ __compute_mvp(mvp, 0, 0, 0);
+
+ scf_logi("%s, x: %d, y: %d, w: %d, h: %d\n", obj->key->data, obj->x, obj->y, obj->w, obj->h);
+
+ GLfloat vert_update[] =
+ {
+ 2.0 * obj->x / (float)width - 1.0,
+ -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+ 2.0 * (obj->x + obj->w) / (float)width - 1.0,
+ -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+ 2.0 * obj->x / (float)width - 1.0,
+ -2.0 * obj->y / (float)height + 1.0,
+
+ 2.0 * (obj->x + obj->w) / (float)width - 1.0,
+ -2.0 * obj->y / (float)height + 1.0,
+ };
+
+ glUseProgram(program);
+ uniform_rgba = glGetUniformLocation(program, "tex_rgba");
+ uniform_mvp = glGetUniformLocation(program, "mvp");
+
+ glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp);
+
+ // board
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture (GL_TEXTURE_2D, texture_rgba);
+ glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, img->width, img->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
+ glUniform1i(uniform_rgba, 0);
+
+ // draw
+ glBindBuffer (GL_ARRAY_BUFFER, buffers[0]);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update);
+
+ glBindVertexArray(vao);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ glBindVertexArray(0);
+ glUseProgram(0);
+
+ abc_img_close(img);
+ free(bgra);
+ return 0;
+}
+
+abc_render_t abc_render_img =
+{
+ .type = ABC_HTML_IMG,
+
+ .draw = _render_draw_img,
+ .fini = _render_fini_img,
+};