Skip to content

Commit 514af11

Browse files
authored
Merge pull request #199 from floooh/sokol-letterbox
Add sample for sokol_letterbox.h
2 parents 1944f0c + 6e688a8 commit 514af11

4 files changed

Lines changed: 182 additions & 26 deletions

File tree

fibs-scripts/sapp.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export const samples: SampleOptions[] = [
7373
deps: ['imgui', 'fileutil', 'basisu'],
7474
jobs: [copy('data/texview', ['kodim05.basis', 'kodim07.basis', 'kodim17.basis', 'kodim20.basis', 'kodim23.basis' ])],
7575
},
76+
{ name: 'letterbox', deps: ['imgui'] },
7677
{ name: 'sgl', ui: 'cc' },
7778
{ name: 'sgl-lines', ui: 'cc' },
7879
{ name: 'sgl-points', ui: 'cc' },

sapp/letterbox-sapp.c

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
//------------------------------------------------------------------------------
2+
// letterbox-sapp.c
3+
//
4+
// Demonstrate/test sokol_letterbox.h
5+
//------------------------------------------------------------------------------
6+
#include "sokol_app.h"
7+
#include "sokol_gfx.h"
8+
#include "sokol_log.h"
9+
#include "sokol_glue.h"
10+
#define SOKOL_GL_IMPL
11+
#include "sokol_gl.h"
12+
#define SOKOL_LETTERBOX_IMPL
13+
#include "sokol_letterbox.h"
14+
#include "cimgui.h"
15+
#define SOKOL_IMGUI_IMPL
16+
#include "sokol_imgui.h"
17+
18+
#define NUM_ANCHORS (5)
19+
20+
static struct {
21+
sg_pass_action pass_action;
22+
slbx_letterbox_desc lbox;
23+
bool link_lr_border;
24+
bool link_tb_border;
25+
int cur_anchor_idx;
26+
struct {
27+
slbx_anchor anchor;
28+
const char* label;
29+
} anchors[NUM_ANCHORS];
30+
} state = {
31+
.pass_action = {
32+
.colors[0] = {
33+
.load_action = SG_LOADACTION_CLEAR,
34+
.clear_value = { 0, 0, 0, 1 },
35+
},
36+
},
37+
.link_lr_border = true,
38+
.link_tb_border = true,
39+
.lbox.content_aspect_ratio = 4.0f / 3.0f,
40+
.anchors = {
41+
{ .anchor = SLBX_ANCHOR_CENTER, .label = "Center" },
42+
{ .anchor = SLBX_ANCHOR_TOP, .label = "Top" },
43+
{ .anchor = SLBX_ANCHOR_BOTTOM, .label = "Bottom" },
44+
{ .anchor = SLBX_ANCHOR_LEFT, .label = "Left" },
45+
{ .anchor = SLBX_ANCHOR_RIGHT, .label = "Right" },
46+
},
47+
};
48+
49+
static void draw_ui(void);
50+
static void main_quad(void);
51+
static void corner_quad(float x, float y);
52+
53+
static void init(void) {
54+
sg_setup(&(sg_desc){
55+
.environment = sglue_environment(),
56+
.logger.func = slog_func,
57+
});
58+
sgl_setup(&(sgl_desc_t){
59+
.logger.func = slog_func,
60+
});
61+
simgui_setup(&(simgui_desc_t){
62+
.logger.func = slog_func,
63+
});
64+
}
65+
66+
static void frame(void) {
67+
draw_ui();
68+
const int width = sapp_width();
69+
const int height = sapp_height();
70+
71+
// draw a letterboxed fullscreen quad via sgl
72+
sgl_defaults();
73+
const slbx_viewport vp = slbx_letterbox(width, height, &state.lbox);
74+
sgl_viewport(vp.x, vp.y, vp.width, vp.height, true);
75+
sgl_begin_quads();
76+
main_quad();
77+
corner_quad(-0.9f, +0.9f);
78+
corner_quad(+0.9f, +0.9f);
79+
corner_quad(+0.9f, -0.9f);
80+
corner_quad(-0.9f, -0.9f);
81+
sgl_end();
82+
sgl_viewport(0, 0, width, height, true);
83+
84+
// render everything in a sokol-gfx pass
85+
sg_begin_pass(&(sg_pass){ .action = state.pass_action, .swapchain = sglue_swapchain() });
86+
sgl_draw();
87+
simgui_render();
88+
sg_end_pass();
89+
sg_commit();
90+
}
91+
92+
static void main_quad(void) {
93+
sgl_v2f_c3b(-1.0f, +1.0f, 255, 0, 0);
94+
sgl_v2f_c3b(+1.0f, +1.0f, 255, 255, 0);
95+
sgl_v2f_c3b(+1.0f, -1.0f, 0, 255, 0);
96+
sgl_v2f_c3b(-1.0f, -1.0f, 0, 255, 255);
97+
}
98+
99+
static void corner_quad(float x, float y) {
100+
float s = 0.05f;
101+
uint8_t r = 255;
102+
uint8_t g = 128;
103+
uint8_t b = 255;
104+
sgl_v2f_c3b(x - s, y + s, r, g, b);
105+
sgl_v2f_c3b(x + s, y + s, r, g, b);
106+
sgl_v2f_c3b(x + s, y - s, r, g, b);
107+
sgl_v2f_c3b(x - s, y - s, r, g, b);
108+
}
109+
110+
static void cleanup(void) {
111+
simgui_shutdown();
112+
sgl_shutdown();
113+
sg_shutdown();
114+
}
115+
116+
static void input(const sapp_event* ev) {
117+
simgui_handle_event(ev);
118+
}
119+
120+
static const char* anchor_getter(void* userdata, int index) {
121+
assert((index >= 0) && (index < NUM_ANCHORS));
122+
(void)userdata;
123+
return state.anchors[index].label;
124+
}
125+
126+
static void draw_ui(void) {
127+
simgui_new_frame(&(simgui_frame_desc_t){
128+
.width = sapp_width(),
129+
.height = sapp_height(),
130+
.delta_time = sapp_frame_duration(),
131+
.dpi_scale = sapp_dpi_scale(),
132+
});
133+
igSetNextWindowPos((ImVec2){ 30, 50 }, ImGuiCond_Once);
134+
igSetNextWindowBgAlpha(0.75f);
135+
if (igBegin("Controls", 0, ImGuiWindowFlags_NoDecoration|ImGuiWindowFlags_AlwaysAutoResize)) {
136+
igText("Resize app window!\n");
137+
igSliderFloat("Content Aspect Ratio", &state.lbox.content_aspect_ratio, 0.5f, 2.0f);
138+
if (igComboCallback("Anchor", &state.cur_anchor_idx, anchor_getter, 0, NUM_ANCHORS)) {
139+
state.lbox.anchor = state.anchors[state.cur_anchor_idx].anchor;
140+
}
141+
igSeparatorText("Border");
142+
igCheckbox("Link Left/Right", &state.link_lr_border);
143+
if (igSliderInt("Left", &state.lbox.border.left, -50, 50) && state.link_lr_border) {
144+
state.lbox.border.right = state.lbox.border.left;
145+
}
146+
if (igSliderInt("Right", &state.lbox.border.right, -50, 50) && state.link_lr_border) {
147+
state.lbox.border.left = state.lbox.border.right;
148+
}
149+
igCheckbox("Link Top/Bottom", &state.link_tb_border);
150+
if (igSliderInt("Top", &state.lbox.border.top, -50, 50) && state.link_tb_border) {
151+
state.lbox.border.bottom = state.lbox.border.top;
152+
}
153+
if (igSliderInt("Bottom", &state.lbox.border.bottom, -50, 50) && state.link_tb_border) {
154+
state.lbox.border.top = state.lbox.border.bottom;
155+
}
156+
}
157+
igEnd();
158+
}
159+
160+
sapp_desc sokol_main(int argc, char* argv[]) {
161+
(void)argc;
162+
(void)argv;
163+
return (sapp_desc){
164+
.init_cb = init,
165+
.frame_cb = frame,
166+
.cleanup_cb = cleanup,
167+
.event_cb = input,
168+
.width = 800,
169+
.height = 600,
170+
.window_title = "letterbox-sapp.c",
171+
.icon.sokol_default = true,
172+
.logger.func = slog_func,
173+
};
174+
}

sapp/texview-sapp.c

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include "sokol_fetch.h"
99
#include "sokol_log.h"
1010
#include "sokol_glue.h"
11+
#define SOKOL_LETTERBOX_IMPL
12+
#include "sokol_letterbox.h"
1113
#include "cimgui.h"
1214
#define SOKOL_IMGUI_IMPL
1315
#include "sokol_imgui.h"
@@ -261,32 +263,11 @@ static void apply_viewport(void) {
261263
if ((state.img_info.width == 0) || (state.img_info.height == 0)) {
262264
return;
263265
}
264-
const float border = 5.0f;
265-
float canvas_width = sapp_widthf() - 2.0f * border;
266-
float canvas_height = sapp_heightf() - 2.0f * border;
267-
if (canvas_width < 1.0f) {
268-
canvas_width = 1.0f;
269-
}
270-
if (canvas_height < 1.0f) {
271-
canvas_height = 1.0f;
272-
}
273-
const float canvas_aspect = canvas_width / canvas_height;
274-
const float img_width = (float)state.img_info.width;
275-
const float img_height = (float)state.img_info.height;
276-
const float img_aspect = img_width / img_height;
277-
float vp_x, vp_y, vp_w, vp_h;
278-
if (img_aspect < canvas_aspect) {
279-
vp_y = border;
280-
vp_h = canvas_height;
281-
vp_w = canvas_height * img_aspect;
282-
vp_x = border + (canvas_width - vp_w) * 0.5f;
283-
} else {
284-
vp_x = border;
285-
vp_w = canvas_width;
286-
vp_h = canvas_width / img_aspect;
287-
vp_y = border + (canvas_height - vp_h) * 0.5f;
288-
}
289-
sg_apply_viewportf(vp_x, vp_y, vp_w, vp_h, true);
266+
const slbx_viewport vp = slbx_letterbox(sapp_width(), sapp_height(), &(slbx_letterbox_desc){
267+
.content_aspect_ratio = (float)state.img_info.width / (float)state.img_info.height,
268+
.border = { .left = 5, .right = 5, .top = 5, .bottom = 5 },
269+
});
270+
sg_apply_viewport(vp.x, vp.y, vp.width, vp.height, true);
290271
}
291272

292273
sapp_desc sokol_main(int argc, char* argv[]) {

webpage/letterbox.jpg

32.6 KB
Loading

0 commit comments

Comments
 (0)