It works!
This commit is contained in:
parent
aa8b2409d9
commit
337526e9b9
1
camera.c
1
camera.c
|
@ -607,6 +607,7 @@ mp_camera_capture_buffer(MPCamera *camera, MPBuffer *buffer)
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
default:
|
default:
|
||||||
errno_printerr("VIDIOC_DQBUF");
|
errno_printerr("VIDIOC_DQBUF");
|
||||||
|
exit(1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
.black {
|
|
||||||
background: #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.errorbox {
|
.errorbox {
|
||||||
background: #dd0000;
|
background: #dd0000;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkDrawingArea" id="preview">
|
<object class="GtkGLArea" id="preview">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can-focus">False</property>
|
<property name="can-focus">False</property>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
@ -0,0 +1,335 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk" version="4.0"/>
|
||||||
|
<object class="GtkAdjustment" id="control_adj">
|
||||||
|
<property name="upper">100</property>
|
||||||
|
<property name="step-increment">1</property>
|
||||||
|
<property name="page-increment">10</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkWindow" id="window">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="default-width">360</property>
|
||||||
|
<property name="default-height">640</property>
|
||||||
|
<property name="decorated">0</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkStack" id="main_stack">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkStackPage">
|
||||||
|
<property name="name">main</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox" id="page_main">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGLArea" id="preview">
|
||||||
|
<property name="vexpand">1</property>
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="control_box">
|
||||||
|
<property name="visible">0</property>
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="hexpand">1</property>
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="margin-start">10</property>
|
||||||
|
<property name="margin-end">10</property>
|
||||||
|
<property name="margin-top">10</property>
|
||||||
|
<property name="margin-bottom">10</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="control_name">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="margin-end">10</property>
|
||||||
|
<property name="label" translatable="yes">ISO</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScale" id="control_slider">
|
||||||
|
<property name="hexpand">1</property>
|
||||||
|
<property name="adjustment">control_adj</property>
|
||||||
|
<property name="round-digits">1</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkToggleButton" id="control_auto">
|
||||||
|
<property name="label" translatable="yes">Auto</property>
|
||||||
|
<property name="receives-default">1</property>
|
||||||
|
<property name="margin-start">10</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="controlbox"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkActionBar" id="controls_box">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<child type="start">
|
||||||
|
<object class="GtkButton" id="settings">
|
||||||
|
<property name="receives-default">1</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="resource">/org/postmarketos/Megapixels/settings-symbolic.svg</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="start">
|
||||||
|
<object class="GtkButton" id="switch_camera">
|
||||||
|
<property name="receives-default">1</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="resource">/org/postmarketos/Megapixels/switch-camera.svg</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="center">
|
||||||
|
<object class="GtkButton" id="shutter">
|
||||||
|
<property name="width-request">48</property>
|
||||||
|
<property name="height-request">48</property>
|
||||||
|
<property name="receives-default">1</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="resource">/org/postmarketos/Megapixels/shutter-button.svg</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="circular"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="end">
|
||||||
|
<object class="GtkButton" id="open_directory">
|
||||||
|
<property name="receives-default">1</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="resource">/org/postmarketos/Megapixels/folder-symbolic.svg</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="end">
|
||||||
|
<object class="GtkButton" id="open_last">
|
||||||
|
<property name="receives-default">1</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkStack" id="open_last_stack">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="thumb_last">
|
||||||
|
<property name="width-request">24</property>
|
||||||
|
<property name="height-request">24</property>
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinner" id="process_spinner">
|
||||||
|
<property name="width-request">24</property>
|
||||||
|
<property name="height-request">24</property>
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="error_box">
|
||||||
|
<property name="visible">0</property>
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="hexpand">1</property>
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="margin-start">10</property>
|
||||||
|
<property name="margin-end">10</property>
|
||||||
|
<property name="margin-top">10</property>
|
||||||
|
<property name="margin-bottom">10</property>
|
||||||
|
<property name="spacing">10</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="error_message">
|
||||||
|
<property name="hexpand">1</property>
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="label" translatable="yes">No error</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="error_close">
|
||||||
|
<property name="label">gtk-close</property>
|
||||||
|
<property name="receives-default">1</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="errorbox"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<!-- <child>
|
||||||
|
<object class="GtkStackPage">
|
||||||
|
<property name="name">settings</property>
|
||||||
|
<property name="title" translatable="yes">page1</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkScrolledWindow" id="page_settings">
|
||||||
|
<property name="shadow-type">in</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkViewport">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="shadow-type">none</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="margin-start">10</property>
|
||||||
|
<property name="margin-end">10</property>
|
||||||
|
<property name="margin-top">10</property>
|
||||||
|
<property name="margin-bottom">10</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">10</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="settings_back">
|
||||||
|
<property name="label" translatable="yes">Back</property>
|
||||||
|
<property name="receives-default">1</property>
|
||||||
|
<property name="margin-start">10</property>
|
||||||
|
<property name="margin-end">10</property>
|
||||||
|
<style>
|
||||||
|
<class name="suggested-action"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="label" translatable="yes">Settings aren't functional yet</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">4</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="label" translatable="yes">Photos</property>
|
||||||
|
<style>
|
||||||
|
<class name="heading"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="shadow-type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="left-padding">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="label" translatable="yes">Resolution</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="label" translatable="yes">Storage mode</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="can-focus">0</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="store_vng">
|
||||||
|
<property name="label" translatable="yes">Debayer with VNG (slowest)</property>
|
||||||
|
<property name="active">1</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="store_simple">
|
||||||
|
<property name="label" translatable="yes">Debayer with linear interpolation</property>
|
||||||
|
<property name="group">store_vng</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="store_raw">
|
||||||
|
<property name="label" translatable="yes">Raw</property>
|
||||||
|
<property name="group">store_vng</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label_item">
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="view"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child> -->
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -11,7 +11,7 @@ capture-rate=10
|
||||||
capture-fmt=BGGR8
|
capture-fmt=BGGR8
|
||||||
preview-width=1280
|
preview-width=1280
|
||||||
preview-height=720
|
preview-height=720
|
||||||
preview-rate=20
|
preview-rate=60
|
||||||
preview-fmt=BGGR8
|
preview-fmt=BGGR8
|
||||||
rotate=270
|
rotate=270
|
||||||
colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050
|
colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050
|
||||||
|
@ -29,11 +29,11 @@ driver=gc2145
|
||||||
media-driver=sun6i-csi
|
media-driver=sun6i-csi
|
||||||
capture-width=1280
|
capture-width=1280
|
||||||
capture-height=960
|
capture-height=960
|
||||||
capture-rate=30
|
capture-rate=60
|
||||||
capture-fmt=BGGR8
|
capture-fmt=BGGR8
|
||||||
preview-width=1280
|
preview-width=1280
|
||||||
preview-height=960
|
preview-height=960
|
||||||
preview-rate=30
|
preview-rate=60
|
||||||
preview-fmt=BGGR8
|
preview-fmt=BGGR8
|
||||||
rotate=90
|
rotate=90
|
||||||
mirrored=true
|
mirrored=true
|
||||||
|
|
|
@ -11,7 +11,7 @@ capture-rate=10
|
||||||
capture-fmt=BGGR8
|
capture-fmt=BGGR8
|
||||||
preview-width=1280
|
preview-width=1280
|
||||||
preview-height=720
|
preview-height=720
|
||||||
preview-rate=20
|
preview-rate=60
|
||||||
preview-fmt=BGGR8
|
preview-fmt=BGGR8
|
||||||
rotate=270
|
rotate=270
|
||||||
colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050
|
colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050
|
||||||
|
@ -29,11 +29,11 @@ driver=gc2145
|
||||||
media-driver=sun6i-csi
|
media-driver=sun6i-csi
|
||||||
capture-width=1280
|
capture-width=1280
|
||||||
capture-height=960
|
capture-height=960
|
||||||
capture-rate=30
|
capture-rate=60
|
||||||
capture-fmt=BGGR8
|
capture-fmt=BGGR8
|
||||||
preview-width=1280
|
preview-width=1280
|
||||||
preview-height=960
|
preview-height=960
|
||||||
preview-rate=30
|
preview-rate=60
|
||||||
preview-fmt=BGGR8
|
preview-fmt=BGGR8
|
||||||
rotate=90
|
rotate=90
|
||||||
mirrored=true
|
mirrored=true
|
||||||
|
|
|
@ -11,7 +11,7 @@ capture-rate=10
|
||||||
capture-fmt=BGGR8
|
capture-fmt=BGGR8
|
||||||
preview-width=1280
|
preview-width=1280
|
||||||
preview-height=720
|
preview-height=720
|
||||||
preview-rate=20
|
preview-rate=60
|
||||||
preview-fmt=BGGR8
|
preview-fmt=BGGR8
|
||||||
rotate=270
|
rotate=270
|
||||||
mirrored=false
|
mirrored=false
|
||||||
|
@ -30,11 +30,11 @@ driver=gc2145
|
||||||
media-driver=sun6i-csi
|
media-driver=sun6i-csi
|
||||||
capture-width=1280
|
capture-width=1280
|
||||||
capture-height=960
|
capture-height=960
|
||||||
capture-rate=30
|
capture-rate=60
|
||||||
capture-fmt=BGGR8
|
capture-fmt=BGGR8
|
||||||
preview-width=1280
|
preview-width=1280
|
||||||
preview-height=960
|
preview-height=960
|
||||||
preview-rate=30
|
preview-rate=60
|
||||||
preview-fmt=BGGR8
|
preview-fmt=BGGR8
|
||||||
rotate=90
|
rotate=90
|
||||||
mirrored=true
|
mirrored=true
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
uniform sampler2D texture;
|
||||||
|
|
||||||
|
varying vec2 uv;
|
||||||
|
|
||||||
|
#define fetch(p) texture2D(texture, p).r
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_FragColor = texture2D(texture, uv);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
attribute vec2 vert;
|
||||||
|
attribute vec2 tex_coord;
|
||||||
|
|
||||||
|
varying vec2 uv;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
uv = tex_coord;
|
||||||
|
|
||||||
|
gl_Position = vec4(vert, 0, 1);
|
||||||
|
}
|
|
@ -1,36 +1,43 @@
|
||||||
precision mediump float;
|
precision highp float;
|
||||||
|
|
||||||
uniform sampler2D texture;
|
uniform sampler2D texture;
|
||||||
// uniform sampler2D srgb_map;
|
uniform sampler2D pixel_layout;
|
||||||
uniform mat3 color_matrix;
|
uniform mat3 color_matrix;
|
||||||
|
|
||||||
varying vec2 uv1;
|
uniform vec2 pixel_size;
|
||||||
varying vec2 uv2;
|
|
||||||
varying vec2 pixel_coord;
|
// varying vec2 uv1;
|
||||||
|
// varying vec2 uv2;
|
||||||
|
varying vec2 top_left_uv;
|
||||||
|
varying vec2 top_right_uv;
|
||||||
|
varying vec2 bottom_left_uv;
|
||||||
|
varying vec2 bottom_right_uv;
|
||||||
|
varying vec2 half_pixel_coord;
|
||||||
|
|
||||||
#define fetch(p) texture2D(texture, p).r
|
#define fetch(p) texture2D(texture, p).r
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 pixels = vec4(
|
vec4 pixels = vec4(
|
||||||
fetch(uv1),
|
fetch(top_left_uv),
|
||||||
fetch(vec2(uv1.x, uv2.y)),
|
fetch(top_right_uv),
|
||||||
fetch(uv2),
|
fetch(bottom_right_uv),
|
||||||
fetch(vec2(uv2.x, uv1.y)));
|
fetch(bottom_left_uv));
|
||||||
|
|
||||||
vec2 arrangement = mod(pixel_coord, 2.0);
|
vec2 arrangement = floor(half_pixel_coord);
|
||||||
|
|
||||||
vec2 is_top_left = step(1.0, arrangement);
|
vec2 is_bottom_left = step(1.0, arrangement);
|
||||||
|
|
||||||
vec3 color = mix(
|
// vec3 color = mix(
|
||||||
mix(pixels.zyx, pixels.wzy, is_top_left.y),
|
// mix(pixels.xyz, pixels.yzw, is_bottom_left.y),
|
||||||
mix(pixels.yzw, pixels.xyz, is_top_left.y),
|
// mix(pixels.wzy, pixels.zyx, is_bottom_left.y),
|
||||||
is_top_left.x);
|
// is_bottom_left.x);
|
||||||
|
vec3 color = pixels.zyx;
|
||||||
|
|
||||||
vec3 srgb_color = pow(color, vec3(1.0 / 2.2));
|
// Fast SRGB estimate. See https://mimosa-pudica.net/fast-gamma/
|
||||||
// vec3 srgb_color = vec3(
|
vec3 srgb_color = (vec3(1.138) * inversesqrt(color) - vec3(0.138)) * color;
|
||||||
// texture2D(srgb_map, vec2(color.r, 0)).r,
|
|
||||||
// texture2D(srgb_map, vec2(color.g, 0)).r,
|
|
||||||
// texture2D(srgb_map, vec2(color.b, 0)).r);
|
|
||||||
|
|
||||||
gl_FragColor = vec4((color_matrix * srgb_color).bgr, 0);
|
// Slow SRGB estimate
|
||||||
|
// vec3 srgb_color = pow(color, vec3(1.0 / 2.2));
|
||||||
|
|
||||||
|
gl_FragColor = vec4(color_matrix * srgb_color, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,32 @@
|
||||||
precision mediump float;
|
precision highp float;
|
||||||
|
|
||||||
attribute vec2 vert;
|
attribute vec2 vert;
|
||||||
attribute vec2 tex_coord;
|
attribute vec2 tex_coord;
|
||||||
|
|
||||||
uniform mat3 transform;
|
uniform mat3 transform;
|
||||||
uniform vec2 pixel_size;
|
uniform vec2 pixel_size;
|
||||||
|
uniform vec2 half_image_size;
|
||||||
|
|
||||||
varying vec2 uv1;
|
// varying vec2 uv1;
|
||||||
varying vec2 uv2;
|
// varying vec2 uv2;
|
||||||
varying vec2 pixel_coord;
|
|
||||||
|
varying vec2 top_left_uv;
|
||||||
|
varying vec2 top_right_uv;
|
||||||
|
varying vec2 bottom_left_uv;
|
||||||
|
varying vec2 bottom_right_uv;
|
||||||
|
varying vec2 half_pixel_coord;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
uv1 = tex_coord - pixel_size / 2.0;
|
top_left_uv = tex_coord - pixel_size / 2.0;
|
||||||
uv2 = tex_coord + pixel_size / 2.0;
|
bottom_right_uv = tex_coord + pixel_size / 2.0;
|
||||||
uv1 += pixel_size;
|
top_right_uv = vec2(top_left_uv.x, bottom_right_uv.y);
|
||||||
uv2 += pixel_size;
|
bottom_left_uv = vec2(bottom_right_uv.x, top_left_uv.y);
|
||||||
pixel_coord = uv1 / pixel_size;
|
|
||||||
|
// uv1 = tex_coord - pixel_size / 2.0;
|
||||||
|
// uv2 = tex_coord + pixel_size / 2.0;
|
||||||
|
// uv1 += pixel_size;
|
||||||
|
// uv2 += pixel_size;
|
||||||
|
half_pixel_coord = top_left_uv * half_image_size;
|
||||||
|
|
||||||
gl_Position = vec4(transform * vec3(vert, 1), 1);
|
gl_Position = vec4(transform * vec3(vert, 1), 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,153 +1,51 @@
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
#include "gl_quickpreview.h"
|
#include "gl_quickpreview.h"
|
||||||
#include "gl_utils.h"
|
#include "gl_utils.h"
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
#define VERTEX_ATTRIBUTE 0
|
#define VERTEX_ATTRIBUTE 0
|
||||||
#define TEX_COORD_ATTRIBUTE 1
|
#define TEX_COORD_ATTRIBUTE 1
|
||||||
|
|
||||||
static const GLfloat square_vertices[] = {
|
|
||||||
-1, -1,
|
|
||||||
1, -1,
|
|
||||||
-1, 1,
|
|
||||||
1, 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const GLfloat square_texcoords[] = {
|
|
||||||
1, 1,
|
|
||||||
1, 0,
|
|
||||||
0, 1,
|
|
||||||
0, 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _GLQuickPreview {
|
struct _GLQuickPreview {
|
||||||
GLuint frame_buffer;
|
GLuint frame_buffer;
|
||||||
GLuint program;
|
GLuint program;
|
||||||
GLuint uniform_transform;
|
GLuint uniform_transform;
|
||||||
GLuint uniform_pixel_size;
|
GLuint uniform_pixel_size;
|
||||||
|
GLuint uniform_half_image_size;
|
||||||
GLuint uniform_texture;
|
GLuint uniform_texture;
|
||||||
|
GLuint uniform_pixel_layout;
|
||||||
GLuint uniform_srgb_map;
|
GLuint uniform_srgb_map;
|
||||||
GLuint uniform_color_matrix;
|
GLuint uniform_color_matrix;
|
||||||
GLuint srgb_texture;
|
|
||||||
|
GLuint pixel_layout_texture_id;
|
||||||
|
uint32_t pixel_layout_texture_width;
|
||||||
|
uint32_t pixel_layout_texture_height;
|
||||||
|
MPPixelFormat pixel_layout_texture_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
static GLuint load_shader(const char *path, GLenum type)
|
|
||||||
{
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
FILE *f = fopen(path, "r");
|
|
||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
GLint size = ftell(f);
|
|
||||||
char *source = malloc(sizeof(char) * size);
|
|
||||||
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
if (fread(source, size, 1, f) == 0) {
|
|
||||||
printf("Failed to read shader file\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint shader = glCreateShader(type);
|
|
||||||
assert(shader != 0);
|
|
||||||
glShaderSource(shader, 1, (const GLchar * const*)&source, &size);
|
|
||||||
glCompileShader(shader);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
// Check compile status
|
|
||||||
GLint success;
|
|
||||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
|
||||||
if (success == GL_FALSE) {
|
|
||||||
printf("Shader compilation failed for %s\n", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint log_length;
|
|
||||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
|
|
||||||
if (log_length > 0) {
|
|
||||||
char *log = malloc(sizeof(char) * log_length);
|
|
||||||
glGetShaderInfoLog(shader, log_length - 1, &log_length, log);
|
|
||||||
|
|
||||||
printf("Shader %s log: %s\n", path, log);
|
|
||||||
free(log);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(source);
|
|
||||||
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static const uint8_t srgb[] = {
|
|
||||||
// 0, 12, 21, 28, 33, 38, 42, 46, 49, 52, 55, 58, 61, 63, 66, 68, 70,
|
|
||||||
// 73, 75, 77, 79, 81, 82, 84, 86, 88, 89, 91, 93, 94, 96, 97, 99, 100,
|
|
||||||
// 102, 103, 104, 106, 107, 109, 110, 111, 112, 114, 115, 116, 117, 118,
|
|
||||||
// 120, 121, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134,
|
|
||||||
// 135, 136, 137, 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147,
|
|
||||||
// 148, 149, 150, 151, 151, 152, 153, 154, 155, 156, 157, 157, 158, 159,
|
|
||||||
// 160, 161, 161, 162, 163, 164, 165, 165, 166, 167, 168, 168, 169, 170,
|
|
||||||
// 171, 171, 172, 173, 174, 174, 175, 176, 176, 177, 178, 179, 179, 180,
|
|
||||||
// 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189,
|
|
||||||
// 190, 191, 191, 192, 193, 193, 194, 194, 195, 196, 196, 197, 197, 198,
|
|
||||||
// 199, 199, 200, 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206,
|
|
||||||
// 207, 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214,
|
|
||||||
// 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222,
|
|
||||||
// 222, 223, 223, 224, 224, 225, 226, 226, 227, 227, 228, 228, 229, 229,
|
|
||||||
// 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236,
|
|
||||||
// 237, 237, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243,
|
|
||||||
// 243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249,
|
|
||||||
// 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255
|
|
||||||
// };
|
|
||||||
|
|
||||||
GLQuickPreview *gl_quick_preview_new()
|
GLQuickPreview *gl_quick_preview_new()
|
||||||
{
|
{
|
||||||
GLuint frame_buffer;
|
GLuint frame_buffer;
|
||||||
glGenFramebuffers(1, &frame_buffer);
|
glGenFramebuffers(1, &frame_buffer);
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
GLuint vert = load_shader("data/debayer.vert", GL_VERTEX_SHADER);
|
GLuint shaders[] = {
|
||||||
GLuint frag = load_shader("data/debayer.frag", GL_FRAGMENT_SHADER);
|
gl_load_shader("data/debayer.vert", GL_VERTEX_SHADER),
|
||||||
|
gl_load_shader("data/debayer.frag", GL_FRAGMENT_SHADER),
|
||||||
GLuint program = glCreateProgram();
|
};
|
||||||
glAttachShader(program, vert);
|
|
||||||
glAttachShader(program, frag);
|
|
||||||
|
|
||||||
|
GLuint program = gl_link_program(shaders, 2);
|
||||||
glBindAttribLocation(program, VERTEX_ATTRIBUTE, "vert");
|
glBindAttribLocation(program, VERTEX_ATTRIBUTE, "vert");
|
||||||
glBindAttribLocation(program, TEX_COORD_ATTRIBUTE, "tex_coord");
|
glBindAttribLocation(program, TEX_COORD_ATTRIBUTE, "tex_coord");
|
||||||
glLinkProgram(program);
|
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
GLint success;
|
|
||||||
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
|
||||||
if (success == GL_FALSE) {
|
|
||||||
printf("Program linking failed\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint log_length;
|
|
||||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
|
|
||||||
if (log_length > 0) {
|
|
||||||
char *log = malloc(sizeof(char) * log_length);
|
|
||||||
glGetProgramInfoLog(program, log_length - 1, &log_length, log);
|
|
||||||
|
|
||||||
printf("Program log: %s\n", log);
|
|
||||||
free(log);
|
|
||||||
}
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
// GLuint srgb_texture;
|
|
||||||
// glGenTextures(1, &srgb_texture);
|
|
||||||
// check_gl();
|
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
// glBindTexture(GL_TEXTURE_2D, srgb_texture);
|
GLuint pixel_layout_texture_id;
|
||||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glGenTextures(1, &pixel_layout_texture_id);
|
||||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
check_gl();
|
||||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
// check_gl();
|
|
||||||
// glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 256, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, srgb);
|
|
||||||
// check_gl();
|
|
||||||
// glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
|
|
||||||
GLQuickPreview *self = malloc(sizeof(GLQuickPreview));
|
GLQuickPreview *self = malloc(sizeof(GLQuickPreview));
|
||||||
self->frame_buffer = frame_buffer;
|
self->frame_buffer = frame_buffer;
|
||||||
|
@ -155,10 +53,18 @@ GLQuickPreview *gl_quick_preview_new()
|
||||||
|
|
||||||
self->uniform_transform = glGetUniformLocation(self->program, "transform");
|
self->uniform_transform = glGetUniformLocation(self->program, "transform");
|
||||||
self->uniform_pixel_size = glGetUniformLocation(self->program, "pixel_size");
|
self->uniform_pixel_size = glGetUniformLocation(self->program, "pixel_size");
|
||||||
|
self->uniform_half_image_size = glGetUniformLocation(self->program, "half_image_size");
|
||||||
self->uniform_texture = glGetUniformLocation(self->program, "texture");
|
self->uniform_texture = glGetUniformLocation(self->program, "texture");
|
||||||
|
self->uniform_pixel_layout = glGetUniformLocation(self->program, "pixel_layout");
|
||||||
self->uniform_color_matrix = glGetUniformLocation(self->program, "color_matrix");
|
self->uniform_color_matrix = glGetUniformLocation(self->program, "color_matrix");
|
||||||
self->uniform_srgb_map = glGetUniformLocation(self->program, "srgb_map");
|
self->uniform_srgb_map = glGetUniformLocation(self->program, "srgb_map");
|
||||||
// self->srgb_texture = srgb_texture;
|
check_gl();
|
||||||
|
|
||||||
|
self->pixel_layout_texture_id = pixel_layout_texture_id;
|
||||||
|
self->pixel_layout_texture_width = 0;
|
||||||
|
self->pixel_layout_texture_height = 0;
|
||||||
|
self->pixel_layout_texture_format = MP_PIXEL_FMT_BGGR8;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +93,36 @@ gl_quick_preview(GLQuickPreview *self,
|
||||||
const float *colormatrix,
|
const float *colormatrix,
|
||||||
const uint8_t blacklevel)
|
const uint8_t blacklevel)
|
||||||
{
|
{
|
||||||
|
// Generate pixel layout image
|
||||||
|
if (src_width != self->pixel_layout_texture_width
|
||||||
|
|| src_height != self->pixel_layout_texture_height
|
||||||
|
|| format != self->pixel_layout_texture_format) {
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, self->pixel_layout_texture_id);
|
||||||
|
|
||||||
|
uint16_t *buffer = malloc(src_width * src_height * sizeof(uint16_t));
|
||||||
|
for (size_t y = 0; y < src_height; ++y) {
|
||||||
|
for (size_t x = 0; x < src_width; ++x) {
|
||||||
|
buffer[x + y * src_width] =
|
||||||
|
(y % 2) == 0
|
||||||
|
? ((x % 2) == 0 ? 0b1111 << 4 : 0b1111 << 8)
|
||||||
|
: ((x % 2) == 0 ? 0b1111 << 8 : 0b1111 << 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_width, src_height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, buffer);
|
||||||
|
check_gl();
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
self->pixel_layout_texture_width = src_width;
|
||||||
|
self->pixel_layout_texture_height = src_height;
|
||||||
|
self->pixel_layout_texture_format = format;
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
check_gl();
|
||||||
|
}
|
||||||
|
|
||||||
assert(ql_quick_preview_supports_format(self, format));
|
assert(ql_quick_preview_supports_format(self, format));
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, self->frame_buffer);
|
glBindFramebuffer(GL_FRAMEBUFFER, self->frame_buffer);
|
||||||
|
@ -202,7 +138,7 @@ gl_quick_preview(GLQuickPreview *self,
|
||||||
glUseProgram(self->program);
|
glUseProgram(self->program);
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
GLfloat rotation_list[4] = { 1, 0, -1, 0 };
|
GLfloat rotation_list[4] = { 0, -1, 0, 1 };
|
||||||
int rotation_index = 4 - rotation / 90;
|
int rotation_index = 4 - rotation / 90;
|
||||||
|
|
||||||
GLfloat sin_rot = rotation_list[rotation_index];
|
GLfloat sin_rot = rotation_list[rotation_index];
|
||||||
|
@ -216,6 +152,9 @@ gl_quick_preview(GLQuickPreview *self,
|
||||||
glUniformMatrix3fv(self->uniform_transform, 1, GL_FALSE, matrix);
|
glUniformMatrix3fv(self->uniform_transform, 1, GL_FALSE, matrix);
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
|
glUniform2f(self->uniform_half_image_size, src_width / 2, src_height / 2);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
GLfloat pixel_size_x = 1.0f / src_width;
|
GLfloat pixel_size_x = 1.0f / src_width;
|
||||||
GLfloat pixel_size_y = 1.0f / src_height;
|
GLfloat pixel_size_y = 1.0f / src_height;
|
||||||
glUniform2f(self->uniform_pixel_size, pixel_size_x, pixel_size_y);
|
glUniform2f(self->uniform_pixel_size, pixel_size_x, pixel_size_y);
|
||||||
|
@ -226,10 +165,10 @@ gl_quick_preview(GLQuickPreview *self,
|
||||||
glUniform1i(self->uniform_texture, 0);
|
glUniform1i(self->uniform_texture, 0);
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
// glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
// glBindTexture(GL_TEXTURE_2D, self->srgb_texture);
|
glBindTexture(GL_TEXTURE_2D, self->pixel_layout_texture_id);
|
||||||
// glUniform1i(self->uniform_srgb_map, 1);
|
glUniform1i(self->uniform_pixel_layout, 1);
|
||||||
// check_gl();
|
check_gl();
|
||||||
|
|
||||||
if (colormatrix)
|
if (colormatrix)
|
||||||
{
|
{
|
||||||
|
@ -250,14 +189,10 @@ gl_quick_preview(GLQuickPreview *self,
|
||||||
glUniformMatrix3fv(self->uniform_color_matrix, 1, GL_FALSE, identity);
|
glUniformMatrix3fv(self->uniform_color_matrix, 1, GL_FALSE, identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
glVertexAttribPointer(VERTEX_ATTRIBUTE, 2, GL_FLOAT, 0, 0, square_vertices);
|
glVertexAttribPointer(VERTEX_ATTRIBUTE, 2, GL_FLOAT, 0, 0, gl_quad_vertices);
|
||||||
check_gl();
|
|
||||||
glEnableVertexAttribArray(VERTEX_ATTRIBUTE);
|
glEnableVertexAttribArray(VERTEX_ATTRIBUTE);
|
||||||
check_gl();
|
glVertexAttribPointer(TEX_COORD_ATTRIBUTE, 2, GL_FLOAT, 0, 0, gl_quad_texcoords);
|
||||||
glVertexAttribPointer(TEX_COORD_ATTRIBUTE, 2, GL_FLOAT, 0, 0, square_texcoords);
|
|
||||||
check_gl();
|
|
||||||
glEnableVertexAttribArray(TEX_COORD_ATTRIBUTE);
|
glEnableVertexAttribArray(TEX_COORD_ATTRIBUTE);
|
||||||
check_gl();
|
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
|
@ -268,8 +203,5 @@ gl_quick_preview(GLQuickPreview *self,
|
||||||
// glBindTexture(GL_TEXTURE_2D, 0);
|
// glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
// glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
// glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
glUseProgram(0);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
#include "gl_utils.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
void __check_gl(const char *file, int line)
|
||||||
|
{
|
||||||
|
GLenum error = glGetError();
|
||||||
|
|
||||||
|
const char *name;
|
||||||
|
switch (error) {
|
||||||
|
case GL_NO_ERROR:
|
||||||
|
return; // no error
|
||||||
|
case GL_INVALID_ENUM:
|
||||||
|
name = "GL_INVALID_ENUM";
|
||||||
|
break;
|
||||||
|
case GL_INVALID_VALUE:
|
||||||
|
name = "GL_INVALID_VALUE";
|
||||||
|
break;
|
||||||
|
case GL_INVALID_OPERATION:
|
||||||
|
name = "GL_INVALID_OPERATION";
|
||||||
|
break;
|
||||||
|
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||||
|
name = "GL_INVALID_FRAMEBUFFER_OPERATION";
|
||||||
|
break;
|
||||||
|
case GL_OUT_OF_MEMORY:
|
||||||
|
name = "GL_OUT_OF_MEMORY";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
name = "UNKNOWN ERROR!";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("GL error at %s:%d - %s\n", file, line, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GLfloat gl_quad_vertices[] = {
|
||||||
|
-1, -1,
|
||||||
|
1, -1,
|
||||||
|
-1, 1,
|
||||||
|
1, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const GLfloat gl_quad_texcoords[] = {
|
||||||
|
0, 0,
|
||||||
|
1, 0,
|
||||||
|
0, 1,
|
||||||
|
1, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
GLuint
|
||||||
|
gl_load_shader(const char *path, GLenum type)
|
||||||
|
{
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
FILE *f = fopen(path, "r");
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
GLint size = ftell(f);
|
||||||
|
char *source = malloc(sizeof(char) * size);
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
if (fread(source, size, 1, f) == 0) {
|
||||||
|
printf("Failed to read shader file\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint shader = glCreateShader(type);
|
||||||
|
assert(shader != 0);
|
||||||
|
glShaderSource(shader, 1, (const GLchar * const*)&source, &size);
|
||||||
|
glCompileShader(shader);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
// Check compile status
|
||||||
|
GLint success;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||||
|
if (success == GL_FALSE) {
|
||||||
|
printf("Shader compilation failed for %s\n", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint log_length;
|
||||||
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if (log_length > 0) {
|
||||||
|
char *log = malloc(sizeof(char) * log_length);
|
||||||
|
glGetShaderInfoLog(shader, log_length - 1, &log_length, log);
|
||||||
|
|
||||||
|
printf("Shader %s log: %s\n", path, log);
|
||||||
|
free(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(source);
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint
|
||||||
|
gl_link_program(GLuint *shaders, size_t num_shaders)
|
||||||
|
{
|
||||||
|
GLuint program = glCreateProgram();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_shaders; ++i) {
|
||||||
|
glAttachShader(program, shaders[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
glLinkProgram(program);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
GLint success;
|
||||||
|
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
||||||
|
if (success == GL_FALSE) {
|
||||||
|
printf("Program linking failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint log_length;
|
||||||
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if (log_length > 0) {
|
||||||
|
char *log = malloc(sizeof(char) * log_length);
|
||||||
|
glGetProgramInfoLog(program, log_length - 1, &log_length, log);
|
||||||
|
|
||||||
|
printf("Program log: %s\n", log);
|
||||||
|
free(log);
|
||||||
|
}
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
return program;
|
||||||
|
}
|
37
gl_utils.h
37
gl_utils.h
|
@ -1,34 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <GLES2/gl2.h>
|
#include <GLES2/gl2.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#define check_gl() __check_gl(__FILE__, __LINE__)
|
#define check_gl() __check_gl(__FILE__, __LINE__)
|
||||||
|
void __check_gl(const char *file, int line);
|
||||||
|
|
||||||
static void __check_gl(const char *file, int line)
|
extern const GLfloat gl_quad_vertices[8];
|
||||||
{
|
extern const GLfloat gl_quad_texcoords[8];
|
||||||
GLenum error = glGetError();
|
|
||||||
|
|
||||||
const char *name;
|
GLuint gl_load_shader(const char *path, GLenum type);
|
||||||
switch (error) {
|
GLuint gl_link_program(GLuint *shaders, size_t num_shaders);
|
||||||
case GL_NO_ERROR:
|
|
||||||
return; // no error
|
|
||||||
case GL_INVALID_ENUM:
|
|
||||||
name = "GL_INVALID_ENUM";
|
|
||||||
break;
|
|
||||||
case GL_INVALID_VALUE:
|
|
||||||
name = "GL_INVALID_VALUE";
|
|
||||||
break;
|
|
||||||
case GL_INVALID_OPERATION:
|
|
||||||
name = "GL_INVALID_OPERATION";
|
|
||||||
break;
|
|
||||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
|
||||||
name = "GL_INVALID_FRAMEBUFFER_OPERATION";
|
|
||||||
break;
|
|
||||||
case GL_OUT_OF_MEMORY:
|
|
||||||
name = "GL_OUT_OF_MEMORY";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
name = "UNKNOWN ERROR!";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("GL error at %s:%d - %s\n", file, line, name);
|
|
||||||
}
|
|
||||||
|
|
599
main.c
599
main.c
|
@ -18,11 +18,20 @@
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <zbar.h>
|
#include <zbar.h>
|
||||||
|
#include "gl_utils.h"
|
||||||
#include "camera_config.h"
|
#include "camera_config.h"
|
||||||
#include "quickpreview.h"
|
#include "quickpreview.h"
|
||||||
#include "io_pipeline.h"
|
#include "io_pipeline.h"
|
||||||
#include "process_pipeline.h"
|
#include "process_pipeline.h"
|
||||||
|
|
||||||
|
#define RENDERDOC
|
||||||
|
|
||||||
|
#ifdef RENDERDOC
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <renderdoc/app.h>
|
||||||
|
RENDERDOC_API_1_1_2 *rdoc_api = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
enum user_control { USER_CONTROL_ISO, USER_CONTROL_SHUTTER };
|
enum user_control { USER_CONTROL_ISO, USER_CONTROL_SHUTTER };
|
||||||
|
|
||||||
static bool camera_is_initialized = false;
|
static bool camera_is_initialized = false;
|
||||||
|
@ -42,7 +51,8 @@ static int exposure;
|
||||||
static bool has_auto_focus_continuous;
|
static bool has_auto_focus_continuous;
|
||||||
static bool has_auto_focus_start;
|
static bool has_auto_focus_start;
|
||||||
|
|
||||||
static cairo_surface_t *surface = NULL;
|
static MPProcessPipelineBuffer *current_preview_buffer = NULL;
|
||||||
|
|
||||||
static cairo_surface_t *status_surface = NULL;
|
static cairo_surface_t *status_surface = NULL;
|
||||||
static char last_path[260] = "";
|
static char last_path[260] = "";
|
||||||
|
|
||||||
|
@ -157,21 +167,21 @@ void mp_main_set_zbar_result(MPZBarScanResult *result)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
set_preview(cairo_surface_t *image)
|
set_preview(MPProcessPipelineBuffer *buffer)
|
||||||
{
|
{
|
||||||
if (surface) {
|
if (current_preview_buffer) {
|
||||||
cairo_surface_destroy(surface);
|
mp_process_pipeline_buffer_unref(current_preview_buffer);
|
||||||
}
|
}
|
||||||
surface = image;
|
current_preview_buffer = buffer;
|
||||||
gtk_widget_queue_draw(preview);
|
gtk_widget_queue_draw(preview);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mp_main_set_preview(cairo_surface_t *image)
|
mp_main_set_preview(MPProcessPipelineBuffer *buffer)
|
||||||
{
|
{
|
||||||
g_main_context_invoke_full(g_main_context_default(), G_PRIORITY_DEFAULT_IDLE,
|
g_main_context_invoke_full(g_main_context_default(), G_PRIORITY_DEFAULT_IDLE,
|
||||||
(GSourceFunc)set_preview, image, NULL);
|
(GSourceFunc)set_preview, buffer, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void transform_centered(cairo_t *cr, uint32_t dst_width, uint32_t dst_height,
|
static void transform_centered(cairo_t *cr, uint32_t dst_width, uint32_t dst_height,
|
||||||
|
@ -210,7 +220,7 @@ capture_completed(struct capture_completed_args *args)
|
||||||
{
|
{
|
||||||
strncpy(last_path, args->fname, 259);
|
strncpy(last_path, args->fname, 259);
|
||||||
|
|
||||||
gtk_image_set_from_surface(GTK_IMAGE(thumb_last), args->thumb);
|
// gtk_image_set_from_surface(GTK_IMAGE(thumb_last), args->thumb);
|
||||||
|
|
||||||
gtk_spinner_stop(GTK_SPINNER(process_spinner));
|
gtk_spinner_stop(GTK_SPINNER(process_spinner));
|
||||||
gtk_stack_set_visible_child(GTK_STACK(open_last_stack), thumb_last);
|
gtk_stack_set_visible_child(GTK_STACK(open_last_stack), thumb_last);
|
||||||
|
@ -234,7 +244,7 @@ mp_main_capture_completed(cairo_surface_t *thumb, const char *fname)
|
||||||
static void
|
static void
|
||||||
draw_controls()
|
draw_controls()
|
||||||
{
|
{
|
||||||
cairo_t *cr;
|
// cairo_t *cr;
|
||||||
char iso[6];
|
char iso[6];
|
||||||
int temp;
|
int temp;
|
||||||
char shutterangle[6];
|
char shutterangle[6];
|
||||||
|
@ -259,72 +269,124 @@ draw_controls()
|
||||||
cairo_surface_destroy(status_surface);
|
cairo_surface_destroy(status_surface);
|
||||||
|
|
||||||
// Make a service to show status of controls, 32px high
|
// Make a service to show status of controls, 32px high
|
||||||
if (gtk_widget_get_window(preview) == NULL) {
|
// if (gtk_widget_get_window(preview) == NULL) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// status_surface =
|
||||||
|
// gdk_window_create_similar_surface(gtk_widget_get_window(preview),
|
||||||
|
// CAIRO_CONTENT_COLOR_ALPHA,
|
||||||
|
// preview_width, 32);
|
||||||
|
|
||||||
|
// cr = cairo_create(status_surface);
|
||||||
|
// cairo_set_source_rgba(cr, 0, 0, 0, 0.0);
|
||||||
|
// cairo_paint(cr);
|
||||||
|
|
||||||
|
// // Draw the outlines for the headings
|
||||||
|
// cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL,
|
||||||
|
// CAIRO_FONT_WEIGHT_BOLD);
|
||||||
|
// cairo_set_font_size(cr, 9);
|
||||||
|
// cairo_set_source_rgba(cr, 0, 0, 0, 1);
|
||||||
|
|
||||||
|
// cairo_move_to(cr, 16, 16);
|
||||||
|
// cairo_text_path(cr, "ISO");
|
||||||
|
// cairo_stroke(cr);
|
||||||
|
|
||||||
|
// cairo_move_to(cr, 60, 16);
|
||||||
|
// cairo_text_path(cr, "Shutter");
|
||||||
|
// cairo_stroke(cr);
|
||||||
|
|
||||||
|
// // Draw the fill for the headings
|
||||||
|
// cairo_set_source_rgba(cr, 1, 1, 1, 1);
|
||||||
|
// cairo_move_to(cr, 16, 16);
|
||||||
|
// cairo_show_text(cr, "ISO");
|
||||||
|
// cairo_move_to(cr, 60, 16);
|
||||||
|
// cairo_show_text(cr, "Shutter");
|
||||||
|
|
||||||
|
// // Draw the outlines for the values
|
||||||
|
// cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL,
|
||||||
|
// CAIRO_FONT_WEIGHT_NORMAL);
|
||||||
|
// cairo_set_font_size(cr, 11);
|
||||||
|
// cairo_set_source_rgba(cr, 0, 0, 0, 1);
|
||||||
|
|
||||||
|
// cairo_move_to(cr, 16, 26);
|
||||||
|
// cairo_text_path(cr, iso);
|
||||||
|
// cairo_stroke(cr);
|
||||||
|
|
||||||
|
// cairo_move_to(cr, 60, 26);
|
||||||
|
// cairo_text_path(cr, shutterangle);
|
||||||
|
// cairo_stroke(cr);
|
||||||
|
|
||||||
|
// // Draw the fill for the values
|
||||||
|
// cairo_set_source_rgba(cr, 1, 1, 1, 1);
|
||||||
|
// cairo_move_to(cr, 16, 26);
|
||||||
|
// cairo_show_text(cr, iso);
|
||||||
|
// cairo_move_to(cr, 60, 26);
|
||||||
|
// cairo_show_text(cr, shutterangle);
|
||||||
|
|
||||||
|
// cairo_destroy(cr);
|
||||||
|
|
||||||
|
// gtk_widget_queue_draw_area(preview, 0, 0, preview_width, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLuint blit_program;
|
||||||
|
static GLuint blit_uniform_texture;
|
||||||
|
|
||||||
|
static void
|
||||||
|
preview_realize(GtkGLArea *area)
|
||||||
|
{
|
||||||
|
gtk_gl_area_make_current(area);
|
||||||
|
|
||||||
|
if (gtk_gl_area_get_error(area) != NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
status_surface =
|
|
||||||
gdk_window_create_similar_surface(gtk_widget_get_window(preview),
|
|
||||||
CAIRO_CONTENT_COLOR_ALPHA,
|
|
||||||
preview_width, 32);
|
|
||||||
|
|
||||||
cr = cairo_create(status_surface);
|
GLuint blit_shaders[] = {
|
||||||
cairo_set_source_rgba(cr, 0, 0, 0, 0.0);
|
gl_load_shader("data/blit.vert", GL_VERTEX_SHADER),
|
||||||
cairo_paint(cr);
|
gl_load_shader("data/blit.frag", GL_FRAGMENT_SHADER),
|
||||||
|
};
|
||||||
|
|
||||||
// Draw the outlines for the headings
|
blit_program = gl_link_program(blit_shaders, 2);
|
||||||
cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL,
|
glBindAttribLocation(blit_program, 0, "vert");
|
||||||
CAIRO_FONT_WEIGHT_BOLD);
|
glBindAttribLocation(blit_program, 1, "tex_coord");
|
||||||
cairo_set_font_size(cr, 9);
|
check_gl();
|
||||||
cairo_set_source_rgba(cr, 0, 0, 0, 1);
|
|
||||||
|
|
||||||
cairo_move_to(cr, 16, 16);
|
blit_uniform_texture = glGetUniformLocation(blit_program, "texture");
|
||||||
cairo_text_path(cr, "ISO");
|
|
||||||
cairo_stroke(cr);
|
|
||||||
|
|
||||||
cairo_move_to(cr, 60, 16);
|
|
||||||
cairo_text_path(cr, "Shutter");
|
|
||||||
cairo_stroke(cr);
|
|
||||||
|
|
||||||
// Draw the fill for the headings
|
|
||||||
cairo_set_source_rgba(cr, 1, 1, 1, 1);
|
|
||||||
cairo_move_to(cr, 16, 16);
|
|
||||||
cairo_show_text(cr, "ISO");
|
|
||||||
cairo_move_to(cr, 60, 16);
|
|
||||||
cairo_show_text(cr, "Shutter");
|
|
||||||
|
|
||||||
// Draw the outlines for the values
|
|
||||||
cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL,
|
|
||||||
CAIRO_FONT_WEIGHT_NORMAL);
|
|
||||||
cairo_set_font_size(cr, 11);
|
|
||||||
cairo_set_source_rgba(cr, 0, 0, 0, 1);
|
|
||||||
|
|
||||||
cairo_move_to(cr, 16, 26);
|
|
||||||
cairo_text_path(cr, iso);
|
|
||||||
cairo_stroke(cr);
|
|
||||||
|
|
||||||
cairo_move_to(cr, 60, 26);
|
|
||||||
cairo_text_path(cr, shutterangle);
|
|
||||||
cairo_stroke(cr);
|
|
||||||
|
|
||||||
// Draw the fill for the values
|
|
||||||
cairo_set_source_rgba(cr, 1, 1, 1, 1);
|
|
||||||
cairo_move_to(cr, 16, 26);
|
|
||||||
cairo_show_text(cr, iso);
|
|
||||||
cairo_move_to(cr, 60, 26);
|
|
||||||
cairo_show_text(cr, shutterangle);
|
|
||||||
|
|
||||||
cairo_destroy(cr);
|
|
||||||
|
|
||||||
gtk_widget_queue_draw_area(preview, 0, 0, preview_width, 32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
preview_draw(GtkWidget *widget, cairo_t *cr, gpointer data)
|
preview_draw(GtkGLArea *area, GdkGLContext *ctx, gpointer data)
|
||||||
{
|
{
|
||||||
|
if (gtk_gl_area_get_error(area) != NULL) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!camera_is_initialized) {
|
if (!camera_is_initialized) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #ifdef RENDERDOC
|
||||||
|
// if (rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL);
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
glClearColor(0, 0, 0, 1);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
if (current_preview_buffer) {
|
||||||
|
glUseProgram(blit_program);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mp_process_pipeline_buffer_get_texture_id(current_preview_buffer));
|
||||||
|
glUniform1i(blit_uniform_texture, 0);
|
||||||
|
|
||||||
|
glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, gl_quad_vertices);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, gl_quad_texcoords);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
check_gl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// Clear preview area with black
|
// Clear preview area with black
|
||||||
cairo_paint(cr);
|
cairo_paint(cr);
|
||||||
|
|
||||||
|
@ -367,19 +429,23 @@ preview_draw(GtkWidget *widget, cairo_t *cr, gpointer data)
|
||||||
// Draw control overlay
|
// Draw control overlay
|
||||||
cairo_set_source_surface(cr, status_surface, 0, 0);
|
cairo_set_source_surface(cr, status_surface, 0, 0);
|
||||||
cairo_paint(cr);
|
cairo_paint(cr);
|
||||||
|
*/
|
||||||
|
|
||||||
|
glFlush();
|
||||||
|
|
||||||
|
// #ifdef RENDERDOC
|
||||||
|
// if(rdoc_api) rdoc_api->EndFrameCapture(NULL, NULL);
|
||||||
|
// #endif
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
preview_configure(GtkWidget *widget, GdkEventConfigure *event)
|
preview_resize(GtkWidget *widget, int width, int height, gpointer data)
|
||||||
{
|
{
|
||||||
int new_preview_width = gtk_widget_get_allocated_width(widget);
|
if (preview_width != width || preview_height != height) {
|
||||||
int new_preview_height = gtk_widget_get_allocated_height(widget);
|
preview_width = width;
|
||||||
|
preview_height = height;
|
||||||
if (preview_width != new_preview_width ||
|
|
||||||
preview_height != new_preview_height) {
|
|
||||||
preview_width = new_preview_width;
|
|
||||||
preview_height = new_preview_height;
|
|
||||||
update_io_pipeline();
|
update_io_pipeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,158 +488,158 @@ on_shutter_clicked(GtkWidget *widget, gpointer user_data)
|
||||||
mp_io_pipeline_capture();
|
mp_io_pipeline_capture();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
// void
|
||||||
on_capture_shortcut(void)
|
// on_capture_shortcut(void)
|
||||||
{
|
// {
|
||||||
on_shutter_clicked(NULL, NULL);
|
// on_shutter_clicked(NULL, NULL);
|
||||||
}
|
// }
|
||||||
|
|
||||||
static bool
|
// static bool
|
||||||
check_point_inside_bounds(int x, int y, int *bounds_x, int *bounds_y)
|
// check_point_inside_bounds(int x, int y, int *bounds_x, int *bounds_y)
|
||||||
{
|
// {
|
||||||
bool right = false, left = false, top = false, bottom = false;
|
// bool right = false, left = false, top = false, bottom = false;
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
// for (int i = 0; i < 4; ++i) {
|
||||||
if (x <= bounds_x[i])
|
// if (x <= bounds_x[i])
|
||||||
left = true;
|
// left = true;
|
||||||
if (x >= bounds_x[i])
|
// if (x >= bounds_x[i])
|
||||||
right = true;
|
// right = true;
|
||||||
if (y <= bounds_y[i])
|
// if (y <= bounds_y[i])
|
||||||
top = true;
|
// top = true;
|
||||||
if (y >= bounds_y[i])
|
// if (y >= bounds_y[i])
|
||||||
bottom = true;
|
// bottom = true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return right && left && top && bottom;
|
// return right && left && top && bottom;
|
||||||
}
|
// }
|
||||||
|
|
||||||
static void
|
// static void
|
||||||
on_zbar_code_tapped(GtkWidget *widget, const MPZBarCode *code)
|
// on_zbar_code_tapped(GtkWidget *widget, const MPZBarCode *code)
|
||||||
{
|
// {
|
||||||
GtkWidget *dialog;
|
// GtkWidget *dialog;
|
||||||
GtkDialogFlags flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT;
|
// GtkDialogFlags flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT;
|
||||||
bool data_is_url = g_uri_is_valid(
|
// bool data_is_url = g_uri_is_valid(
|
||||||
code->data, G_URI_FLAGS_PARSE_RELAXED, NULL);
|
// code->data, G_URI_FLAGS_PARSE_RELAXED, NULL);
|
||||||
|
|
||||||
char* data = strdup(code->data);
|
// char* data = strdup(code->data);
|
||||||
|
|
||||||
if (data_is_url) {
|
// if (data_is_url) {
|
||||||
dialog = gtk_message_dialog_new(
|
// dialog = gtk_message_dialog_new(
|
||||||
GTK_WINDOW(gtk_widget_get_toplevel(widget)),
|
// GTK_WINDOW(gtk_widget_get_toplevel(widget)),
|
||||||
flags,
|
// flags,
|
||||||
GTK_MESSAGE_QUESTION,
|
// GTK_MESSAGE_QUESTION,
|
||||||
GTK_BUTTONS_NONE,
|
// GTK_BUTTONS_NONE,
|
||||||
"Found a URL '%s' encoded in a %s code.",
|
// "Found a URL '%s' encoded in a %s code.",
|
||||||
code->data,
|
// code->data,
|
||||||
code->type);
|
// code->type);
|
||||||
gtk_dialog_add_buttons(
|
// gtk_dialog_add_buttons(
|
||||||
GTK_DIALOG(dialog),
|
// GTK_DIALOG(dialog),
|
||||||
"_Open URL",
|
// "_Open URL",
|
||||||
GTK_RESPONSE_YES,
|
// GTK_RESPONSE_YES,
|
||||||
NULL);
|
// NULL);
|
||||||
} else {
|
// } else {
|
||||||
dialog = gtk_message_dialog_new(
|
// dialog = gtk_message_dialog_new(
|
||||||
GTK_WINDOW(gtk_widget_get_toplevel(widget)),
|
// GTK_WINDOW(gtk_widget_get_toplevel(widget)),
|
||||||
flags,
|
// flags,
|
||||||
GTK_MESSAGE_QUESTION,
|
// GTK_MESSAGE_QUESTION,
|
||||||
GTK_BUTTONS_NONE,
|
// GTK_BUTTONS_NONE,
|
||||||
"Found '%s' encoded in a %s code.",
|
// "Found '%s' encoded in a %s code.",
|
||||||
code->data,
|
// code->data,
|
||||||
code->type);
|
// code->type);
|
||||||
}
|
// }
|
||||||
gtk_dialog_add_buttons(
|
// gtk_dialog_add_buttons(
|
||||||
GTK_DIALOG(dialog),
|
// GTK_DIALOG(dialog),
|
||||||
"_Copy",
|
// "_Copy",
|
||||||
GTK_RESPONSE_ACCEPT,
|
// GTK_RESPONSE_ACCEPT,
|
||||||
"_Cancel",
|
// "_Cancel",
|
||||||
GTK_RESPONSE_CANCEL,
|
// GTK_RESPONSE_CANCEL,
|
||||||
NULL);
|
// NULL);
|
||||||
|
|
||||||
int result = gtk_dialog_run(GTK_DIALOG(dialog));
|
// int result = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||||
|
|
||||||
GError *error = NULL;
|
// GError *error = NULL;
|
||||||
switch (result) {
|
// switch (result) {
|
||||||
case GTK_RESPONSE_YES:
|
// case GTK_RESPONSE_YES:
|
||||||
if (!g_app_info_launch_default_for_uri(data,
|
// if (!g_app_info_launch_default_for_uri(data,
|
||||||
NULL, &error)) {
|
// NULL, &error)) {
|
||||||
g_printerr("Could not launch application: %s\n",
|
// g_printerr("Could not launch application: %s\n",
|
||||||
error->message);
|
// error->message);
|
||||||
}
|
// }
|
||||||
case GTK_RESPONSE_ACCEPT:
|
// case GTK_RESPONSE_ACCEPT:
|
||||||
gtk_clipboard_set_text(
|
// gtk_clipboard_set_text(
|
||||||
gtk_clipboard_get(GDK_SELECTION_PRIMARY),
|
// gtk_clipboard_get(GDK_SELECTION_PRIMARY),
|
||||||
data, -1);
|
// data, -1);
|
||||||
case GTK_RESPONSE_CANCEL:
|
// case GTK_RESPONSE_CANCEL:
|
||||||
break;
|
// break;
|
||||||
default:
|
// default:
|
||||||
g_printerr("Wrong dialog result: %d\n", result);
|
// g_printerr("Wrong dialog result: %d\n", result);
|
||||||
}
|
// }
|
||||||
gtk_widget_destroy(dialog);
|
// gtk_widget_destroy(dialog);
|
||||||
}
|
// }
|
||||||
|
|
||||||
void
|
// void
|
||||||
on_preview_tap(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
|
// on_preview_tap(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
|
||||||
{
|
// {
|
||||||
if (event->type != GDK_BUTTON_PRESS)
|
// if (event->type != GDK_BUTTON_PRESS)
|
||||||
return;
|
// return;
|
||||||
|
|
||||||
// Handle taps on the controls
|
// // Handle taps on the controls
|
||||||
if (event->y < 32) {
|
// if (event->y < 32) {
|
||||||
if (gtk_widget_is_visible(control_box)) {
|
// if (gtk_widget_is_visible(control_box)) {
|
||||||
gtk_widget_hide(control_box);
|
// gtk_widget_hide(control_box);
|
||||||
return;
|
// return;
|
||||||
} else {
|
// } else {
|
||||||
gtk_widget_show(control_box);
|
// gtk_widget_show(control_box);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (event->x < 60) {
|
// if (event->x < 60) {
|
||||||
// ISO
|
// // ISO
|
||||||
current_control = USER_CONTROL_ISO;
|
// current_control = USER_CONTROL_ISO;
|
||||||
gtk_label_set_text(GTK_LABEL(control_name), "ISO");
|
// gtk_label_set_text(GTK_LABEL(control_name), "ISO");
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(control_auto),
|
// gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(control_auto),
|
||||||
!gain_is_manual);
|
// !gain_is_manual);
|
||||||
gtk_adjustment_set_lower(control_slider, 0.0);
|
// gtk_adjustment_set_lower(control_slider, 0.0);
|
||||||
gtk_adjustment_set_upper(control_slider, (float)gain_max);
|
// gtk_adjustment_set_upper(control_slider, (float)gain_max);
|
||||||
gtk_adjustment_set_value(control_slider, (double)gain);
|
// gtk_adjustment_set_value(control_slider, (double)gain);
|
||||||
|
|
||||||
} else if (event->x > 60 && event->x < 120) {
|
// } else if (event->x > 60 && event->x < 120) {
|
||||||
// Shutter angle
|
// // Shutter angle
|
||||||
current_control = USER_CONTROL_SHUTTER;
|
// current_control = USER_CONTROL_SHUTTER;
|
||||||
gtk_label_set_text(GTK_LABEL(control_name), "Shutter");
|
// gtk_label_set_text(GTK_LABEL(control_name), "Shutter");
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(control_auto),
|
// gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(control_auto),
|
||||||
!exposure_is_manual);
|
// !exposure_is_manual);
|
||||||
gtk_adjustment_set_lower(control_slider, 1.0);
|
// gtk_adjustment_set_lower(control_slider, 1.0);
|
||||||
gtk_adjustment_set_upper(control_slider, 360.0);
|
// gtk_adjustment_set_upper(control_slider, 360.0);
|
||||||
gtk_adjustment_set_value(control_slider, (double)exposure);
|
// gtk_adjustment_set_value(control_slider, (double)exposure);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Tapped zbar result
|
// // Tapped zbar result
|
||||||
if (zbar_result) {
|
// if (zbar_result) {
|
||||||
// Transform the event coordinates to the image
|
// // Transform the event coordinates to the image
|
||||||
int width = cairo_image_surface_get_width(surface);
|
// int width = cairo_image_surface_get_width(surface);
|
||||||
int height = cairo_image_surface_get_height(surface);
|
// int height = cairo_image_surface_get_height(surface);
|
||||||
double scale = MIN(preview_width / (double)width, preview_height / (double)height);
|
// double scale = MIN(preview_width / (double)width, preview_height / (double)height);
|
||||||
int x = (event->x - preview_width / 2) / scale + width / 2;
|
// int x = (event->x - preview_width / 2) / scale + width / 2;
|
||||||
int y = (event->y - preview_height / 2) / scale + height / 2;
|
// int y = (event->y - preview_height / 2) / scale + height / 2;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < zbar_result->size; ++i) {
|
// for (uint8_t i = 0; i < zbar_result->size; ++i) {
|
||||||
MPZBarCode *code = &zbar_result->codes[i];
|
// MPZBarCode *code = &zbar_result->codes[i];
|
||||||
|
|
||||||
if (check_point_inside_bounds(x, y, code->bounds_x, code->bounds_y)) {
|
// if (check_point_inside_bounds(x, y, code->bounds_x, code->bounds_y)) {
|
||||||
on_zbar_code_tapped(widget, code);
|
// on_zbar_code_tapped(widget, code);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Tapped preview image itself, try focussing
|
// // Tapped preview image itself, try focussing
|
||||||
if (has_auto_focus_start) {
|
// if (has_auto_focus_start) {
|
||||||
mp_io_pipeline_focus();
|
// mp_io_pipeline_focus();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
void
|
void
|
||||||
on_error_close_clicked(GtkWidget *widget, gpointer user_data)
|
on_error_close_clicked(GtkWidget *widget, gpointer user_data)
|
||||||
|
@ -690,22 +756,35 @@ on_control_slider_changed(GtkAdjustment *widget, gpointer user_data)
|
||||||
static void
|
static void
|
||||||
on_realize(GtkWidget *window, gpointer *data)
|
on_realize(GtkWidget *window, gpointer *data)
|
||||||
{
|
{
|
||||||
mp_process_pipeline_init_gl(gtk_widget_get_window(window));
|
GtkNative *native = gtk_widget_get_native(window);
|
||||||
|
mp_process_pipeline_init_gl(gtk_native_get_surface(native));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
typedef struct
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
{
|
||||||
if (!mp_load_config())
|
GtkApplication parent_instance;
|
||||||
return 1;
|
} MegapixelsApp;
|
||||||
|
|
||||||
setenv("LC_NUMERIC", "C", 1);
|
typedef GtkApplicationClass MegapixelsAppClass;
|
||||||
|
|
||||||
|
GType megapixels_app_get_type (void);
|
||||||
|
G_DEFINE_TYPE(MegapixelsApp, megapixels_app, GTK_TYPE_APPLICATION)
|
||||||
|
|
||||||
|
static void
|
||||||
|
startup(GApplication *app)
|
||||||
|
{
|
||||||
|
G_APPLICATION_CLASS(megapixels_app_parent_class)->startup(app);
|
||||||
|
|
||||||
gtk_init(&argc, &argv);
|
|
||||||
g_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme",
|
g_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme",
|
||||||
TRUE, NULL);
|
TRUE, NULL);
|
||||||
GtkBuilder *builder = gtk_builder_new_from_resource(
|
|
||||||
"/org/postmarketos/Megapixels/camera.glade");
|
GtkBuilder *builder;
|
||||||
|
if (access("camera.ui", F_OK) != -1) {
|
||||||
|
builder = gtk_builder_new_from_file("camera.ui");
|
||||||
|
} else {
|
||||||
|
builder = gtk_builder_new_from_file(
|
||||||
|
"/org/postmarketos/Megapixels/camera.ui");
|
||||||
|
}
|
||||||
|
|
||||||
GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
|
GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
|
||||||
GtkWidget *shutter = GTK_WIDGET(gtk_builder_get_object(builder, "shutter"));
|
GtkWidget *shutter = GTK_WIDGET(gtk_builder_get_object(builder, "shutter"));
|
||||||
|
@ -734,7 +813,7 @@ main(int argc, char *argv[])
|
||||||
GTK_ADJUSTMENT(gtk_builder_get_object(builder, "control_adj"));
|
GTK_ADJUSTMENT(gtk_builder_get_object(builder, "control_adj"));
|
||||||
control_auto = GTK_WIDGET(gtk_builder_get_object(builder, "control_auto"));
|
control_auto = GTK_WIDGET(gtk_builder_get_object(builder, "control_auto"));
|
||||||
g_signal_connect(window, "realize", G_CALLBACK(on_realize), NULL);
|
g_signal_connect(window, "realize", G_CALLBACK(on_realize), NULL);
|
||||||
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
// g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
||||||
g_signal_connect(shutter, "clicked", G_CALLBACK(on_shutter_clicked), NULL);
|
g_signal_connect(shutter, "clicked", G_CALLBACK(on_shutter_clicked), NULL);
|
||||||
g_signal_connect(error_close, "clicked", G_CALLBACK(on_error_close_clicked),
|
g_signal_connect(error_close, "clicked", G_CALLBACK(on_error_close_clicked),
|
||||||
NULL);
|
NULL);
|
||||||
|
@ -748,14 +827,15 @@ main(int argc, char *argv[])
|
||||||
NULL);
|
NULL);
|
||||||
g_signal_connect(open_directory, "clicked",
|
g_signal_connect(open_directory, "clicked",
|
||||||
G_CALLBACK(on_open_directory_clicked), NULL);
|
G_CALLBACK(on_open_directory_clicked), NULL);
|
||||||
g_signal_connect(preview, "draw", G_CALLBACK(preview_draw), NULL);
|
g_signal_connect(preview, "realize", G_CALLBACK(preview_realize), NULL);
|
||||||
g_signal_connect(preview, "configure-event", G_CALLBACK(preview_configure),
|
g_signal_connect(preview, "render", G_CALLBACK(preview_draw), NULL);
|
||||||
NULL);
|
g_signal_connect(preview, "resize", G_CALLBACK(preview_resize),
|
||||||
gtk_widget_set_events(preview, gtk_widget_get_events(preview) |
|
|
||||||
GDK_BUTTON_PRESS_MASK |
|
|
||||||
GDK_POINTER_MOTION_MASK);
|
|
||||||
g_signal_connect(preview, "button-press-event", G_CALLBACK(on_preview_tap),
|
|
||||||
NULL);
|
NULL);
|
||||||
|
// gtk_widget_set_events(preview, gtk_widget_get_events(preview) |
|
||||||
|
// GDK_BUTTON_PRESS_MASK |
|
||||||
|
// GDK_POINTER_MOTION_MASK);
|
||||||
|
// g_signal_connect(preview, "button-press-event", G_CALLBACK(on_preview_tap),
|
||||||
|
// NULL);
|
||||||
g_signal_connect(control_auto, "toggled",
|
g_signal_connect(control_auto, "toggled",
|
||||||
G_CALLBACK(on_control_auto_toggled), NULL);
|
G_CALLBACK(on_control_auto_toggled), NULL);
|
||||||
g_signal_connect(control_slider, "value-changed",
|
g_signal_connect(control_slider, "value-changed",
|
||||||
|
@ -763,7 +843,7 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
GtkCssProvider *provider = gtk_css_provider_new();
|
GtkCssProvider *provider = gtk_css_provider_new();
|
||||||
if (access("camera.css", F_OK) != -1) {
|
if (access("camera.css", F_OK) != -1) {
|
||||||
gtk_css_provider_load_from_path(provider, "camera.css", NULL);
|
gtk_css_provider_load_from_path(provider, "camera.css");
|
||||||
} else {
|
} else {
|
||||||
gtk_css_provider_load_from_resource(
|
gtk_css_provider_load_from_resource(
|
||||||
provider, "/org/postmarketos/Megapixels/camera.css");
|
provider, "/org/postmarketos/Megapixels/camera.css");
|
||||||
|
@ -775,26 +855,81 @@ main(int argc, char *argv[])
|
||||||
gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider),
|
gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider),
|
||||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||||
|
|
||||||
GClosure* capture_shortcut = g_cclosure_new(on_capture_shortcut, 0, 0);
|
// GClosure* capture_shortcut = g_cclosure_new(on_capture_shortcut, 0, 0);
|
||||||
|
|
||||||
GtkAccelGroup* accel_group = gtk_accel_group_new();
|
// GtkAccelGroup* accel_group = gtk_accel_group_new();
|
||||||
gtk_accel_group_connect(accel_group,
|
// gtk_accel_group_connect(accel_group,
|
||||||
GDK_KEY_space,
|
// GDK_KEY_space,
|
||||||
0,
|
// 0,
|
||||||
0,
|
// 0,
|
||||||
capture_shortcut);
|
// capture_shortcut);
|
||||||
|
|
||||||
gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
|
// gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
|
||||||
|
|
||||||
mp_io_pipeline_start();
|
mp_io_pipeline_start();
|
||||||
|
|
||||||
camera = mp_get_camera_config(0);
|
camera = mp_get_camera_config(0);
|
||||||
update_io_pipeline();
|
update_io_pipeline();
|
||||||
|
|
||||||
|
gtk_application_add_window(GTK_APPLICATION(app), GTK_WINDOW(window));
|
||||||
gtk_widget_show(window);
|
gtk_widget_show(window);
|
||||||
gtk_main();
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shutdown(GApplication *app)
|
||||||
|
{
|
||||||
|
// Only do cleanup in development, let the OS clean up otherwise
|
||||||
|
#ifdef DEBUG
|
||||||
mp_io_pipeline_stop();
|
mp_io_pipeline_stop();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
G_APPLICATION_CLASS(megapixels_app_parent_class)->shutdown(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
megapixels_app_init(MegapixelsApp *app)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
megapixels_app_class_init(MegapixelsAppClass *class)
|
||||||
|
{
|
||||||
|
GApplicationClass *application_class = G_APPLICATION_CLASS(class);
|
||||||
|
|
||||||
|
application_class->startup = startup;
|
||||||
|
application_class->shutdown = shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
#ifdef RENDERDOC
|
||||||
|
{
|
||||||
|
void *mod = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD);
|
||||||
|
if (mod)
|
||||||
|
{
|
||||||
|
pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)dlsym(mod, "RENDERDOC_GetAPI");
|
||||||
|
int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api);
|
||||||
|
assert(ret == 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Renderdoc not found\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!mp_load_config())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
setenv("LC_NUMERIC", "C", 1);
|
||||||
|
|
||||||
|
MegapixelsApp *app = g_object_new(
|
||||||
|
megapixels_app_get_type(),
|
||||||
|
"application-id", "org.postmarketos.Megapixels",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_application_run(G_APPLICATION(app), argc, argv);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
3
main.h
3
main.h
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "camera_config.h"
|
#include "camera_config.h"
|
||||||
#include "zbar_pipeline.h"
|
#include "zbar_pipeline.h"
|
||||||
|
#include "process_pipeline.h"
|
||||||
#include "gtk/gtk.h"
|
#include "gtk/gtk.h"
|
||||||
|
|
||||||
#define MP_MAIN_THUMB_SIZE 24
|
#define MP_MAIN_THUMB_SIZE 24
|
||||||
|
@ -23,7 +24,7 @@ struct mp_main_state {
|
||||||
|
|
||||||
void mp_main_update_state(const struct mp_main_state *state);
|
void mp_main_update_state(const struct mp_main_state *state);
|
||||||
|
|
||||||
void mp_main_set_preview(cairo_surface_t *image);
|
void mp_main_set_preview(MPProcessPipelineBuffer *buffer);
|
||||||
void mp_main_capture_completed(cairo_surface_t *thumb, const char *fname);
|
void mp_main_capture_completed(cairo_surface_t *thumb, const char *fname);
|
||||||
|
|
||||||
void mp_main_set_zbar_result(MPZBarScanResult *result);
|
void mp_main_set_zbar_result(MPZBarScanResult *result);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
project('megapixels', 'c')
|
project('megapixels', 'c')
|
||||||
gnome = import('gnome')
|
gnome = import('gnome')
|
||||||
gtkdep = dependency('gtk+-3.0')
|
gtkdep = dependency('gtk4')
|
||||||
tiff = dependency('libtiff-4')
|
tiff = dependency('libtiff-4')
|
||||||
zbar = dependency('zbar')
|
zbar = dependency('zbar')
|
||||||
threads = dependency('threads')
|
threads = dependency('threads')
|
||||||
|
@ -34,6 +34,7 @@ executable('megapixels',
|
||||||
'ini.c',
|
'ini.c',
|
||||||
'quickpreview.c',
|
'quickpreview.c',
|
||||||
'gl_quickpreview.c',
|
'gl_quickpreview.c',
|
||||||
|
'gl_utils.c',
|
||||||
'camera.c',
|
'camera.c',
|
||||||
'device.c',
|
'device.c',
|
||||||
'pipeline.c',
|
'pipeline.c',
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "gl_utils.h"
|
#include "gl_utils.h"
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
#include <gdk/gdkwayland.h>
|
// #include <gdk/gdkwayland.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <drm/drm_fourcc.h>
|
#include <drm/drm_fourcc.h>
|
||||||
|
|
||||||
|
@ -151,130 +151,100 @@ mp_process_pipeline_sync()
|
||||||
|
|
||||||
#define NUM_BUFFERS 4
|
#define NUM_BUFFERS 4
|
||||||
|
|
||||||
|
struct _MPProcessPipelineBuffer {
|
||||||
|
GLuint texture_id;
|
||||||
|
|
||||||
|
_Atomic(int) refcount;
|
||||||
|
};
|
||||||
|
static MPProcessPipelineBuffer output_buffers[NUM_BUFFERS];
|
||||||
|
|
||||||
|
static int output_buffer_width = 0;
|
||||||
|
static int output_buffer_height = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
mp_process_pipeline_buffer_ref(MPProcessPipelineBuffer *buf)
|
||||||
|
{
|
||||||
|
++buf->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mp_process_pipeline_buffer_unref(MPProcessPipelineBuffer *buf)
|
||||||
|
{
|
||||||
|
--buf->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
mp_process_pipeline_buffer_get_texture_id(MPProcessPipelineBuffer *buf)
|
||||||
|
{
|
||||||
|
return buf->texture_id;
|
||||||
|
}
|
||||||
|
|
||||||
static GLQuickPreview *gl_quick_preview_state = NULL;
|
static GLQuickPreview *gl_quick_preview_state = NULL;
|
||||||
|
|
||||||
static EGLDisplay egl_display = EGL_NO_DISPLAY;
|
static GdkGLContext *context;
|
||||||
static EGLContext egl_context = EGL_NO_CONTEXT;
|
|
||||||
|
|
||||||
// struct buffer {
|
|
||||||
// GLuint texture_id;
|
|
||||||
// EGLImage egl_image;
|
|
||||||
// int dma_fd;
|
|
||||||
// int dma_stride;
|
|
||||||
// int dma_offset;
|
|
||||||
// void *data;
|
|
||||||
// };
|
|
||||||
// static struct buffer input_buffers[NUM_BUFFERS];
|
|
||||||
// static struct buffer output_buffers[NUM_BUFFERS];
|
|
||||||
|
|
||||||
static PFNEGLEXPORTDMABUFIMAGEMESAPROC eglExportDMABUFImageMESA;
|
static PFNEGLEXPORTDMABUFIMAGEMESAPROC eglExportDMABUFImageMESA;
|
||||||
static PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC eglExportDMABUFImageQueryMESA;
|
static PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC eglExportDMABUFImageQueryMESA;
|
||||||
|
|
||||||
static const char *
|
// static const char *
|
||||||
egl_get_error_str()
|
// egl_get_error_str()
|
||||||
{
|
// {
|
||||||
EGLint error = eglGetError();
|
// EGLint error = eglGetError();
|
||||||
switch (error) {
|
// switch (error) {
|
||||||
case EGL_SUCCESS: return "EGL_SUCCESS";
|
// case EGL_SUCCESS: return "EGL_SUCCESS";
|
||||||
case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
|
// case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
|
||||||
case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
|
// case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
|
||||||
case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
|
// case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
|
||||||
case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
|
// case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
|
||||||
case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
|
// case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
|
||||||
case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
|
// case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
|
||||||
case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
|
// case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
|
||||||
case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
|
// case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
|
||||||
case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
|
// case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
|
||||||
case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
|
// case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
|
||||||
case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
|
// case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
|
||||||
case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
|
// case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
|
||||||
case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
|
// case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
|
||||||
case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
|
// case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
|
||||||
}
|
// }
|
||||||
return "Unknown";
|
// return "Unknown";
|
||||||
}
|
// }
|
||||||
|
|
||||||
#define RENDERDOC
|
#define RENDERDOC
|
||||||
|
|
||||||
#ifdef RENDERDOC
|
#ifdef RENDERDOC
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <renderdoc/app.h>
|
#include <renderdoc/app.h>
|
||||||
RENDERDOC_API_1_1_2 *rdoc_api = NULL;
|
extern RENDERDOC_API_1_1_2 *rdoc_api;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_gl(MPPipeline *pipeline, GdkWindow **window)
|
init_gl(MPPipeline *pipeline, GdkSurface **surface)
|
||||||
{
|
{
|
||||||
#ifdef RENDERDOC
|
GError *error = NULL;
|
||||||
{
|
context = gdk_surface_create_gl_context(*surface, &error);
|
||||||
void *mod = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD);
|
if (context == NULL) {
|
||||||
if (mod)
|
printf("Failed to initialize OpenGL context: %s\n", error->message);
|
||||||
{
|
g_clear_error(&error);
|
||||||
pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)dlsym(mod, "RENDERDOC_GetAPI");
|
return;
|
||||||
int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api);
|
|
||||||
assert(ret == 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Renderdoc not found\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gdk_gl_context_set_use_es(context, true);
|
||||||
|
gdk_gl_context_set_required_version(context, 2, 0);
|
||||||
|
#ifdef DEBUG
|
||||||
|
gdk_gl_context_set_debug_enabled(context, true);
|
||||||
|
#else
|
||||||
|
gdk_gl_context_set_debug_enabled(context, false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GdkDisplay *gdk_display = gdk_window_get_display(*window);
|
gdk_gl_context_realize(context, &error);
|
||||||
egl_display = eglGetDisplay((EGLNativeDisplayType) gdk_wayland_display_get_wl_display(gdk_display));
|
if (error != NULL) {
|
||||||
assert(egl_display != EGL_NO_DISPLAY);
|
printf("Failed to create OpenGL context: %s\n", error->message);
|
||||||
|
g_clear_object(&context);
|
||||||
EGLint major, minor;
|
g_clear_error(&error);
|
||||||
if (!eglInitialize(egl_display, &major, &minor)) {
|
|
||||||
printf("Failed to initialize egl: %s\n", egl_get_error_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!eglBindAPI(EGL_OPENGL_ES_API)) {
|
|
||||||
printf("Failed to bind OpenGL ES: %s\n", egl_get_error_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("extensions: %s\n", eglQueryString(egl_display, EGL_EXTENSIONS));
|
|
||||||
|
|
||||||
EGLint config_attrs[1] = {
|
|
||||||
EGL_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
EGLConfig config;
|
|
||||||
EGLint num_configs = 0;
|
|
||||||
if (!eglChooseConfig(egl_display, config_attrs, &config, 1, &num_configs)) {
|
|
||||||
printf("Failed to pick a egl config: %s\n", egl_get_error_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_configs != 1) {
|
|
||||||
printf("No egl configs found: %s\n", egl_get_error_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGLint context_attrs[5] = {
|
|
||||||
EGL_CONTEXT_CLIENT_VERSION,
|
|
||||||
2,
|
|
||||||
EGL_CONTEXT_FLAGS_KHR,
|
|
||||||
EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR,
|
|
||||||
EGL_NONE,
|
|
||||||
};
|
|
||||||
|
|
||||||
egl_context = eglCreateContext(egl_display, config, NULL, context_attrs);
|
|
||||||
|
|
||||||
if (egl_context == EGL_NO_CONTEXT) {
|
|
||||||
printf("Failed to create OpenGL ES context: %s\n", egl_get_error_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_context))
|
|
||||||
{
|
|
||||||
printf("Failed to set current OpenGL context: %s\n", egl_get_error_str());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gdk_gl_context_make_current(context);
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
eglExportDMABUFImageMESA = (PFNEGLEXPORTDMABUFIMAGEMESAPROC)
|
eglExportDMABUFImageMESA = (PFNEGLEXPORTDMABUFIMAGEMESAPROC)
|
||||||
|
@ -300,153 +270,154 @@ init_gl(MPPipeline *pipeline, GdkWindow **window)
|
||||||
gl_quick_preview_state = gl_quick_preview_new();
|
gl_quick_preview_state = gl_quick_preview_new();
|
||||||
check_gl();
|
check_gl();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < NUM_BUFFERS; ++i) {
|
||||||
|
glGenTextures(1, &output_buffers[i].texture_id);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, output_buffers[i].texture_id);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
printf("Initialized OpenGL\n");
|
printf("Initialized OpenGL\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mp_process_pipeline_init_gl(GdkWindow *window)
|
mp_process_pipeline_init_gl(GdkSurface *surface)
|
||||||
{
|
{
|
||||||
mp_pipeline_invoke(pipeline, (MPPipelineCallback) init_gl, &window, sizeof(GdkWindow *));
|
mp_pipeline_invoke(pipeline, (MPPipelineCallback) init_gl, &surface, sizeof(GdkSurface *));
|
||||||
}
|
}
|
||||||
|
|
||||||
static cairo_surface_t *
|
static cairo_surface_t *
|
||||||
process_image_for_preview(const uint8_t *image)
|
process_image_for_preview(const uint8_t *image)
|
||||||
{
|
{
|
||||||
cairo_surface_t *surface;
|
|
||||||
|
|
||||||
clock_t t1 = clock();
|
clock_t t1 = clock();
|
||||||
|
|
||||||
if (gl_quick_preview_state && ql_quick_preview_supports_format(gl_quick_preview_state, mode.pixel_format)) {
|
assert(gl_quick_preview_state && ql_quick_preview_supports_format(gl_quick_preview_state, mode.pixel_format));
|
||||||
#ifdef RENDERDOC
|
|
||||||
if (rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL);
|
|
||||||
#endif
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
GLuint textures[2];
|
// Pick an available buffer
|
||||||
glGenTextures(2, textures);
|
MPProcessPipelineBuffer *output_buffer = NULL;
|
||||||
|
for (size_t i = 0; i < NUM_BUFFERS; ++i) {
|
||||||
glBindTexture(GL_TEXTURE_2D, textures[0]);
|
if (output_buffers[i].refcount == 0) {
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
output_buffer = &output_buffers[i];
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
}
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, mode.width, mode.height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textures[1]);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, preview_width, preview_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
gl_quick_preview(
|
|
||||||
gl_quick_preview_state,
|
|
||||||
textures[1], preview_width, preview_height,
|
|
||||||
textures[0], mode.width, mode.height,
|
|
||||||
mode.pixel_format,
|
|
||||||
camera->rotate, camera->mirrored,
|
|
||||||
camera->previewmatrix[0] == 0 ? NULL : camera->previewmatrix,
|
|
||||||
camera->blacklevel);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
surface = cairo_image_surface_create(
|
|
||||||
CAIRO_FORMAT_RGB24, preview_width, preview_height);
|
|
||||||
uint32_t *pixels = (uint32_t *)cairo_image_surface_get_data(surface);
|
|
||||||
glFinish();
|
|
||||||
|
|
||||||
clock_t t2 = clock();
|
|
||||||
printf("%fms\n", (float)(t2 - t1) / CLOCKS_PER_SEC * 1000);
|
|
||||||
|
|
||||||
// {
|
|
||||||
// glBindTexture(GL_TEXTURE_2D, textures[1]);
|
|
||||||
// EGLImage egl_image = eglCreateImage(egl_display, egl_context, EGL_GL_TEXTURE_2D, (EGLClientBuffer)(size_t)textures[1], NULL);
|
|
||||||
|
|
||||||
// // Make sure it's in the expected format
|
|
||||||
// int fourcc;
|
|
||||||
// eglExportDMABUFImageQueryMESA(egl_display, egl_image, &fourcc, NULL, NULL);
|
|
||||||
// assert(fourcc == DRM_FORMAT_ABGR8888);
|
|
||||||
|
|
||||||
|
|
||||||
// int dmabuf_fd;
|
|
||||||
// int stride, offset;
|
|
||||||
// eglExportDMABUFImageMESA(egl_display, egl_image, &dmabuf_fd, &stride, &offset);
|
|
||||||
|
|
||||||
// int fsize = lseek(dmabuf_fd, 0, SEEK_END);
|
|
||||||
// printf("SIZE %d STRIDE %d OFFSET %d SIZE %d:%d\n", fsize, stride, offset, preview_width, preview_height);
|
|
||||||
|
|
||||||
// size_t size = stride * preview_height;
|
|
||||||
// uint32_t *data = mmap(NULL, fsize, PROT_READ, MAP_SHARED, dmabuf_fd, 0);
|
|
||||||
// assert(data != MAP_FAILED);
|
|
||||||
|
|
||||||
// int pixel_stride = stride / 4;
|
|
||||||
|
|
||||||
// for (size_t y = 0; y < preview_height; ++y) {
|
|
||||||
// for (size_t x = 0; x < preview_width; ++x) {
|
|
||||||
// uint32_t p = data[x + y * pixel_stride];
|
|
||||||
// pixels[x + y * preview_width] = p;
|
|
||||||
// // uint16_t p = data[x + y * stride];
|
|
||||||
// // uint32_t r = (p & 0b11111);
|
|
||||||
// // uint32_t g = ((p >> 5) & 0b11111);
|
|
||||||
// // uint32_t b = ((p >> 10) & 0b11111);
|
|
||||||
// // pixels[x + y * preview_width] = (r << 16) | (g << 8) | b;
|
|
||||||
// }
|
|
||||||
// // memcpy(pixels + preview_width * y, data + stride * y, preview_width * sizeof(uint32_t));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// {
|
|
||||||
// FILE *f = fopen("test.raw", "w");
|
|
||||||
// fwrite(data, fsize, 1, f);
|
|
||||||
// fclose(f);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // memcpy(pixels, data, size);
|
|
||||||
// munmap(data, size);
|
|
||||||
// close(dmabuf_fd);
|
|
||||||
// }
|
|
||||||
glReadPixels(0, 0, preview_width, preview_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
|
||||||
check_gl();
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
|
|
||||||
#ifdef RENDERDOC
|
|
||||||
if(rdoc_api) rdoc_api->EndFrameCapture(NULL, NULL);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
uint32_t surface_width, surface_height, skip;
|
|
||||||
quick_preview_size(&surface_width, &surface_height, &skip, preview_width,
|
|
||||||
preview_height, mode.width, mode.height,
|
|
||||||
mode.pixel_format, camera->rotate);
|
|
||||||
|
|
||||||
surface = cairo_image_surface_create(
|
|
||||||
CAIRO_FORMAT_RGB24, surface_width, surface_height);
|
|
||||||
|
|
||||||
uint8_t *pixels = cairo_image_surface_get_data(surface);
|
|
||||||
|
|
||||||
quick_preview((uint32_t *)pixels, surface_width, surface_height, image,
|
|
||||||
mode.width, mode.height, mode.pixel_format,
|
|
||||||
camera->rotate, camera->mirrored,
|
|
||||||
camera->previewmatrix[0] == 0 ? NULL : camera->previewmatrix,
|
|
||||||
camera->blacklevel, skip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (output_buffer == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
assert(output_buffer != NULL);
|
||||||
|
|
||||||
|
#ifdef RENDERDOC
|
||||||
|
if (rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL);
|
||||||
|
#endif
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
// Copy image to a GL texture. TODO: This can be avoided
|
||||||
|
GLuint input_texture;
|
||||||
|
glGenTextures(1, &input_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, input_texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, mode.width, mode.height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
|
||||||
|
gl_quick_preview(
|
||||||
|
gl_quick_preview_state,
|
||||||
|
output_buffer->texture_id, output_buffer_width, output_buffer_height,
|
||||||
|
input_texture, mode.width, mode.height,
|
||||||
|
mode.pixel_format,
|
||||||
|
camera->rotate, camera->mirrored,
|
||||||
|
camera->previewmatrix[0] == 0 ? NULL : camera->previewmatrix,
|
||||||
|
camera->blacklevel);
|
||||||
|
check_gl();
|
||||||
|
|
||||||
|
// surface = cairo_image_surface_create(
|
||||||
|
// CAIRO_FORMAT_RGB24, preview_width, preview_height);
|
||||||
|
// uint32_t *pixels = (uint32_t *)cairo_image_surface_get_data(surface);
|
||||||
|
glFinish();
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
clock_t t2 = clock();
|
||||||
|
printf("%fms\n", (float)(t2 - t1) / CLOCKS_PER_SEC * 1000);
|
||||||
|
|
||||||
|
// {
|
||||||
|
// glBindTexture(GL_TEXTURE_2D, textures[1]);
|
||||||
|
// EGLImage egl_image = eglCreateImage(egl_display, egl_context, EGL_GL_TEXTURE_2D, (EGLClientBuffer)(size_t)textures[1], NULL);
|
||||||
|
|
||||||
|
// // Make sure it's in the expected format
|
||||||
|
// int fourcc;
|
||||||
|
// eglExportDMABUFImageQueryMESA(egl_display, egl_image, &fourcc, NULL, NULL);
|
||||||
|
// assert(fourcc == DRM_FORMAT_ABGR8888);
|
||||||
|
|
||||||
|
|
||||||
|
// int dmabuf_fd;
|
||||||
|
// int stride, offset;
|
||||||
|
// eglExportDMABUFImageMESA(egl_display, egl_image, &dmabuf_fd, &stride, &offset);
|
||||||
|
|
||||||
|
// int fsize = lseek(dmabuf_fd, 0, SEEK_END);
|
||||||
|
// printf("SIZE %d STRIDE %d OFFSET %d SIZE %d:%d\n", fsize, stride, offset, preview_width, preview_height);
|
||||||
|
|
||||||
|
// size_t size = stride * preview_height;
|
||||||
|
// uint32_t *data = mmap(NULL, fsize, PROT_READ, MAP_SHARED, dmabuf_fd, 0);
|
||||||
|
// assert(data != MAP_FAILED);
|
||||||
|
|
||||||
|
// int pixel_stride = stride / 4;
|
||||||
|
|
||||||
|
// for (size_t y = 0; y < preview_height; ++y) {
|
||||||
|
// for (size_t x = 0; x < preview_width; ++x) {
|
||||||
|
// uint32_t p = data[x + y * pixel_stride];
|
||||||
|
// pixels[x + y * preview_width] = p;
|
||||||
|
// // uint16_t p = data[x + y * stride];
|
||||||
|
// // uint32_t r = (p & 0b11111);
|
||||||
|
// // uint32_t g = ((p >> 5) & 0b11111);
|
||||||
|
// // uint32_t b = ((p >> 10) & 0b11111);
|
||||||
|
// // pixels[x + y * preview_width] = (r << 16) | (g << 8) | b;
|
||||||
|
// }
|
||||||
|
// // memcpy(pixels + preview_width * y, data + stride * y, preview_width * sizeof(uint32_t));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// {
|
||||||
|
// FILE *f = fopen("test.raw", "w");
|
||||||
|
// fwrite(data, fsize, 1, f);
|
||||||
|
// fclose(f);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // memcpy(pixels, data, size);
|
||||||
|
// munmap(data, size);
|
||||||
|
// close(dmabuf_fd);
|
||||||
|
// }
|
||||||
|
// glReadPixels(0, 0, preview_width, preview_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
// check_gl();
|
||||||
|
|
||||||
|
#ifdef RENDERDOC
|
||||||
|
if(rdoc_api) rdoc_api->EndFrameCapture(NULL, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mp_process_pipeline_buffer_ref(output_buffer);
|
||||||
|
mp_main_set_preview(output_buffer);
|
||||||
|
|
||||||
// Create a thumbnail from the preview for the last capture
|
// Create a thumbnail from the preview for the last capture
|
||||||
cairo_surface_t *thumb = NULL;
|
cairo_surface_t *thumb = NULL;
|
||||||
if (captures_remaining == 1) {
|
// if (captures_remaining == 1) {
|
||||||
printf("Making thumbnail\n");
|
// printf("Making thumbnail\n");
|
||||||
thumb = cairo_image_surface_create(
|
// thumb = cairo_image_surface_create(
|
||||||
CAIRO_FORMAT_ARGB32, MP_MAIN_THUMB_SIZE, MP_MAIN_THUMB_SIZE);
|
// CAIRO_FORMAT_ARGB32, MP_MAIN_THUMB_SIZE, MP_MAIN_THUMB_SIZE);
|
||||||
|
|
||||||
cairo_t *cr = cairo_create(thumb);
|
// cairo_t *cr = cairo_create(thumb);
|
||||||
draw_surface_scaled_centered(
|
// draw_surface_scaled_centered(
|
||||||
cr, MP_MAIN_THUMB_SIZE, MP_MAIN_THUMB_SIZE, surface);
|
// cr, MP_MAIN_THUMB_SIZE, MP_MAIN_THUMB_SIZE, surface);
|
||||||
cairo_destroy(cr);
|
// cairo_destroy(cr);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Pass processed preview to main and zbar
|
// Pass processed preview to main and zbar
|
||||||
mp_zbar_pipeline_process_image(cairo_surface_reference(surface));
|
// mp_zbar_pipeline_process_image(cairo_surface_reference(surface));
|
||||||
mp_main_set_preview(surface);
|
|
||||||
|
|
||||||
return thumb;
|
return thumb;
|
||||||
}
|
}
|
||||||
|
@ -755,17 +726,39 @@ mp_process_pipeline_capture()
|
||||||
mp_pipeline_invoke(pipeline, capture, NULL, 0);
|
mp_pipeline_invoke(pipeline, capture, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_output_buffers()
|
||||||
|
{
|
||||||
|
output_buffer_width = mode.width / 2;
|
||||||
|
output_buffer_height = mode.height / 2;
|
||||||
|
|
||||||
|
if (camera->rotate != 0 || camera->rotate != 180) {
|
||||||
|
int tmp = output_buffer_width;
|
||||||
|
output_buffer_width = output_buffer_height;
|
||||||
|
output_buffer_height = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < NUM_BUFFERS; ++i) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, output_buffers[i].texture_id);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, output_buffer_width, output_buffer_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state)
|
update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state)
|
||||||
{
|
{
|
||||||
|
const bool buffer_update_required = (!mp_camera_mode_is_equivalent(&mode, &state->mode) || preview_width != state->preview_width || preview_height != state->preview_height);
|
||||||
|
|
||||||
camera = state->camera;
|
camera = state->camera;
|
||||||
mode = state->mode;
|
mode = state->mode;
|
||||||
|
|
||||||
burst_length = state->burst_length;
|
|
||||||
|
|
||||||
preview_width = state->preview_width;
|
preview_width = state->preview_width;
|
||||||
preview_height = state->preview_height;
|
preview_height = state->preview_height;
|
||||||
|
|
||||||
|
burst_length = state->burst_length;
|
||||||
|
|
||||||
// gain_is_manual = state->gain_is_manual;
|
// gain_is_manual = state->gain_is_manual;
|
||||||
gain = state->gain;
|
gain = state->gain;
|
||||||
gain_max = state->gain_max;
|
gain_max = state->gain_max;
|
||||||
|
@ -773,6 +766,10 @@ update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state
|
||||||
exposure_is_manual = state->exposure_is_manual;
|
exposure_is_manual = state->exposure_is_manual;
|
||||||
exposure = state->exposure;
|
exposure = state->exposure;
|
||||||
|
|
||||||
|
if (buffer_update_required) {
|
||||||
|
update_output_buffers();
|
||||||
|
}
|
||||||
|
|
||||||
struct mp_main_state main_state = {
|
struct mp_main_state main_state = {
|
||||||
.camera = camera,
|
.camera = camera,
|
||||||
.mode = mode,
|
.mode = mode,
|
||||||
|
@ -793,3 +790,6 @@ mp_process_pipeline_update_state(const struct mp_process_pipeline_state *new_sta
|
||||||
mp_pipeline_invoke(pipeline, (MPPipelineCallback)update_state, new_state,
|
mp_pipeline_invoke(pipeline, (MPPipelineCallback)update_state, new_state,
|
||||||
sizeof(struct mp_process_pipeline_state));
|
sizeof(struct mp_process_pipeline_state));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUCK YOU GTK
|
||||||
|
void pango_fc_font_get_languages() {}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include "camera_config.h"
|
#include "camera_config.h"
|
||||||
|
|
||||||
typedef struct _GdkWindow GdkWindow;
|
typedef struct _GdkSurface GdkSurface;
|
||||||
|
|
||||||
struct mp_process_pipeline_state {
|
struct mp_process_pipeline_state {
|
||||||
const struct mp_camera_config *camera;
|
const struct mp_camera_config *camera;
|
||||||
|
@ -28,8 +28,14 @@ void mp_process_pipeline_start();
|
||||||
void mp_process_pipeline_stop();
|
void mp_process_pipeline_stop();
|
||||||
void mp_process_pipeline_sync();
|
void mp_process_pipeline_sync();
|
||||||
|
|
||||||
void mp_process_pipeline_init_gl(GdkWindow *window);
|
void mp_process_pipeline_init_gl(GdkSurface *window);
|
||||||
|
|
||||||
void mp_process_pipeline_process_image(MPBuffer buffer);
|
void mp_process_pipeline_process_image(MPBuffer buffer);
|
||||||
void mp_process_pipeline_capture();
|
void mp_process_pipeline_capture();
|
||||||
void mp_process_pipeline_update_state(const struct mp_process_pipeline_state *state);
|
void mp_process_pipeline_update_state(const struct mp_process_pipeline_state *state);
|
||||||
|
|
||||||
|
typedef struct _MPProcessPipelineBuffer MPProcessPipelineBuffer;
|
||||||
|
|
||||||
|
void mp_process_pipeline_buffer_ref(MPProcessPipelineBuffer *buf);
|
||||||
|
void mp_process_pipeline_buffer_unref(MPProcessPipelineBuffer *buf);
|
||||||
|
uint32_t mp_process_pipeline_buffer_get_texture_id(MPProcessPipelineBuffer *buf);
|
||||||
|
|
Loading…
Reference in New Issue