From ac0be97139206ad9006ec15603e2c81de5043ea0 Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Wed, 18 Feb 2015 12:13:07 +0100 Subject: [PATCH 01/13] add a structure to hold shader parameters state --- .../linux/apps/raspicam/RaspiTexUtil.h | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/host_applications/linux/apps/raspicam/RaspiTexUtil.h b/host_applications/linux/apps/raspicam/RaspiTexUtil.h index cf5dfb30b..3ff3e21d1 100644 --- a/host_applications/linux/apps/raspicam/RaspiTexUtil.h +++ b/host_applications/linux/apps/raspicam/RaspiTexUtil.h @@ -43,6 +43,19 @@ extern VCOS_LOG_CAT_T raspitex_log_category; #define SHADER_MAX_ATTRIBUTES 16 #define SHADER_MAX_UNIFORMS 16 + +typedef struct RASPITEXUTIL_SHADER_PARAMETER_T +{ + // Variables for the, uh, variables + // stolen from puredata/gem glsl_program.h, thanks guys ;-) + GLint size; + GLenum type; + GLint loc; + GLchar *name; + GLfloat param[16]; + int flag; +} RASPITEXUTIL_SHADER_PARAMETER_T; + /** * Container for a simple shader program. The uniform and attribute locations * are automatically setup by raspitex_build_shader_program. @@ -51,7 +64,16 @@ typedef struct RASPITEXUTIL_SHADER_PROGRAM_T { const char *vertex_source; /// Pointer to vertex shader source const char *fragment_source; /// Pointer to fragment shader source + + GLint max_length; /// Maximum length of parameter name; + GLint uniform_count, attribute_count; /// Number of parameters + + char* fragment_shader_filename; + char* vertex_shader_filename; + /// Array of shader paramaters (uniform and attributes) + RASPITEXUTIL_SHADER_PARAMETER_T *uniform_array, *attribute_array; + /// Array of uniform names for raspitex_build_shader_program to process const char *uniform_names[SHADER_MAX_UNIFORMS]; /// Array of attribute names for raspitex_build_shader_program to process @@ -112,5 +134,6 @@ void raspitexutil_close(RASPITEX_STATE* raspitex_state); /* Utility functions */ int raspitexutil_build_shader_program(RASPITEXUTIL_SHADER_PROGRAM_T *p); void raspitexutil_brga_to_rgba(uint8_t *buffer, size_t size); +void raspitexutil_create_param_array(RASPITEXUTIL_SHADER_PROGRAM_T *p); #endif /* RASPITEX_UTIL_H_ */ From 04225cf17e9c1ba0a1d603ef811bbfc318a3a60c Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Wed, 18 Feb 2015 12:14:42 +0100 Subject: [PATCH 02/13] add method to create array of shader parameters and automatically fill it work only with uniform for now TODO : support varying --- .../linux/apps/raspicam/RaspiTexUtil.c | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/host_applications/linux/apps/raspicam/RaspiTexUtil.c b/host_applications/linux/apps/raspicam/RaspiTexUtil.c index 120fef6fc..4e101baa1 100644 --- a/host_applications/linux/apps/raspicam/RaspiTexUtil.c +++ b/host_applications/linux/apps/raspicam/RaspiTexUtil.c @@ -582,7 +582,25 @@ int raspitexutil_build_shader_program(RASPITEXUTIL_SHADER_PROGRAM_T *p) } } - return 0; + /// Automatically find uniform variables + glGetProgramiv( p->program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &p->max_length); + glGetProgramiv( p->program, GL_ACTIVE_UNIFORMS, &p->uniform_count); + printf("found %d uniform variable(s) : \n",p->uniform_count); + + raspitexutil_create_param_array(p); + + GLchar *name= (GLchar*) malloc(sizeof(GLchar)*p->max_length); + GLsizei length=0; + RASPITEXUTIL_SHADER_PARAMETER_T *array = p->uniform_array; + for(i=0;iuniform_count;i++){ + glGetActiveUniform(p->program, i, p->max_length, &length, &array[i].size, &array[i].type, name); + array[i].loc = glGetUniformLocation( p->program, name ); + strncpy(array[i].name,name,length+1); + printf("\t%s\n",name); + } + free(name); + + return 0; fail: vcos_log_error("%s: Failed to build shader program", VCOS_FUNCTION); @@ -595,3 +613,38 @@ int raspitexutil_build_shader_program(RASPITEXUTIL_SHADER_PROGRAM_T *p) return -1; } +void raspitexutil_create_param_array(RASPITEXUTIL_SHADER_PROGRAM_T *p) +{ + + int i; + + p->uniform_array = (RASPITEXUTIL_SHADER_PARAMETER_T*) malloc(sizeof (RASPITEXUTIL_SHADER_PARAMETER_T) * p->uniform_count); + p->attribute_array = (RASPITEXUTIL_SHADER_PARAMETER_T*) malloc(sizeof (RASPITEXUTIL_SHADER_PARAMETER_T) * p->attribute_count); + + RASPITEXUTIL_SHADER_PARAMETER_T* array = p->uniform_array; + // allocate maximum size for a param, which is a 4x4 matrix of floats + // in the future, only allocate for specific type + // also, technically we should handle arrays of matrices, too...sheesh! + for (i = 0; i < p->uniform_count; i++) { + int j=0; + array[i].size = 0; + array[i].type = 0; + array[i].loc = 0; + // uniform_array[i].param = (float*) malloc(sizeof(float)*16); + array[i].name = (GLchar*) malloc(sizeof(GLchar)* p->max_length+1);; + array[i].flag = 0; + for(j=0; j<16; j++)array[i].param[j]=0; + } + + array = p->attribute_array; + for (i = 0; i < p->attribute_count; i++) { + int j=0; + array[i].size = 0; + array[i].type = 0; + array[i].loc = 0; + // attribute_array[i].param = (float*) malloc(sizeof(float)*16); + array[i].name = (GLchar*) malloc(sizeof(GLchar)* p->max_length+1); + array[i].flag = 0; + for(j=0; j<16; j++)array[i].param[j]=0; + } +} From eed9739e34785f7542dd36d909a4f28b49fcefc7 Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Wed, 18 Feb 2015 12:19:13 +0100 Subject: [PATCH 03/13] add an OpenGL scene --- .../linux/apps/raspicam/RaspiStill.c | 57 ++++++++++++++++++- .../linux/apps/raspicam/RaspiTex.c | 8 ++- .../linux/apps/raspicam/RaspiTex.h | 5 +- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/host_applications/linux/apps/raspicam/RaspiStill.c b/host_applications/linux/apps/raspicam/RaspiStill.c index 74f16624b..ca4e452c5 100644 --- a/host_applications/linux/apps/raspicam/RaspiStill.c +++ b/host_applications/linux/apps/raspicam/RaspiStill.c @@ -78,6 +78,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include "gl_scenes/shader.h" // Standard port setting for the camera component #define MMAL_CAMERA_PREVIEW_PORT 0 #define MMAL_CAMERA_VIDEO_PORT 1 @@ -189,6 +190,8 @@ static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag); #define CommandCamSelect 20 #define CommandBurstMode 21 #define CommandSensorMode 22 +#define CommandFragmentShader 24 +#define CommandVertexShader 25 static COMMAND_LIST cmdline_commands[] = { @@ -215,6 +218,8 @@ static COMMAND_LIST cmdline_commands[] = { CommandCamSelect, "-camselect","cs", "Select camera . Default 0", 1 }, { CommandBurstMode, "-burst", "bm", "Enable 'burst capture mode'", 0}, { CommandSensorMode,"-mode", "md", "Force sensor mode. 0=auto. See docs for other modes available", 1}, + { CommandFragmentShader, "-fragmentshader", "frag", "fragment shader program file", 1 }, + { CommandVertexShader, "-fragmentshader", "vert", "vertex shader program file", 1 }, }; static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]); @@ -636,8 +641,56 @@ static int parse_cmdline(int argc, const char **argv, RASPISTILL_STATE *state) valid = 0; break; } - - + + case CommandOSCport: // Set OSC port (only valid with shader scene) + { + int len = strlen(argv[i + 1]); + if (len) + { + state->osc_inport = malloc(len+1); // leave enough space for any timelapse generated changes to filename + vcos_assert(state->osc_inport); + if (state->osc_inport) + strncpy(state->osc_inport, argv[i + 1], len+1); + i++; + state->useOSC=1; + } + else + valid = 0; + break; + } + + case CommandFragmentShader: // Set fragment shader file to load + { + int len = strlen(argv[i + 1]); + if (len) + { + state->raspitex_state.fragment_shader_filename = malloc(len+1); // leave enough space for any timelapse generated changes to filename + vcos_assert(state->raspitex_state->fragment_shader_filename); + if (state->raspitex_state.fragment_shader_filename) + strncpy(state->raspitex_state.fragment_shader_filename, argv[i + 1], len+1); + i++; + } + else + valid = 0; + break; + } + + case CommandVertexShader: // Set vertex shader file to load + { + int len = strlen(argv[i + 1]); + if (len) + { + state->raspitex_state.vertex_shader_filename = malloc(len+1); // leave enough space for any timelapse generated changes to filename + vcos_assert(state->raspitex_state->vertex_shader_filename); + if (state->raspitex_state.vertex_shader_filename) + strncpy(state->raspitex_state.vertex_shader_filename, argv[i + 1], len+1); + i++; + } + else + valid = 0; + break; + } + default: { // Try parsing for any image specific parameters diff --git a/host_applications/linux/apps/raspicam/RaspiTex.c b/host_applications/linux/apps/raspicam/RaspiTex.c index c8af79632..e15bdce9d 100644 --- a/host_applications/linux/apps/raspicam/RaspiTex.c +++ b/host_applications/linux/apps/raspicam/RaspiTex.c @@ -49,6 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "gl_scenes/square.h" #include "gl_scenes/teapot.h" #include "gl_scenes/yuv.h" +#include "gl_scenes/shader.h" /** * \file RaspiTex.c @@ -97,7 +98,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static COMMAND_LIST cmdline_commands[] = { - { CommandGLScene, "-glscene", "gs", "GL scene square,teapot,mirror,yuv,sobel", 1 }, + { CommandGLScene, "-glscene", "gs", "GL scene square,teapot,mirror,yuv,sobel,shader", 1 }, { CommandGLWin, "-glwin", "gw", "GL window settings <'x,y,w,h'>", 1 }, }; @@ -159,6 +160,8 @@ int raspitex_parse_cmdline(RASPITEX_STATE *state, state->scene_id = RASPITEX_SCENE_YUV; else if (strcmp(arg2, "sobel") == 0) state->scene_id = RASPITEX_SCENE_SOBEL; + else if (strcmp(arg2, "shader") == 0) + state->scene_id = RASPITEX_SCENE_SHADER; else vcos_log_error("Unknown scene %s", arg2); @@ -585,6 +588,9 @@ int raspitex_init(RASPITEX_STATE *state) case RASPITEX_SCENE_SOBEL: rc = sobel_open(state); break; + case RASPITEX_SCENE_SHADER: + rc = shader_open(state); + break; default: rc = -1; break; diff --git a/host_applications/linux/apps/raspicam/RaspiTex.h b/host_applications/linux/apps/raspicam/RaspiTex.h index b177417cb..b0dbb844a 100644 --- a/host_applications/linux/apps/raspicam/RaspiTex.h +++ b/host_applications/linux/apps/raspicam/RaspiTex.h @@ -46,6 +46,7 @@ typedef enum { RASPITEX_SCENE_TEAPOT, RASPITEX_SCENE_YUV, RASPITEX_SCENE_SOBEL, + RASPITEX_SCENE_SHADER, } RASPITEX_SCENE_T; @@ -173,7 +174,9 @@ typedef struct RASPITEX_STATE int verbose; /// Log FPS RASPITEX_CAPTURE capture; /// Frame-buffer capture state - + char* fragment_shader_filename; + char* vertex_shader_filename; + } RASPITEX_STATE; int raspitex_init(RASPITEX_STATE *state); From a859fd31f91e4cfe5242376363d4c23086d5174c Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Wed, 18 Feb 2015 12:24:03 +0100 Subject: [PATCH 04/13] include the new scene in build system --- host_applications/linux/apps/raspicam/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/host_applications/linux/apps/raspicam/CMakeLists.txt b/host_applications/linux/apps/raspicam/CMakeLists.txt index f00cef98b..fca8a8063 100644 --- a/host_applications/linux/apps/raspicam/CMakeLists.txt +++ b/host_applications/linux/apps/raspicam/CMakeLists.txt @@ -12,7 +12,8 @@ set (GL_SCENE_SOURCES gl_scenes/yuv.c gl_scenes/sobel.c gl_scenes/square.c - gl_scenes/teapot.c) + gl_scenes/teapot.c + gl_scenes/shader.c) set (COMMON_SOURCES RaspiCamControl.c From b2331ed76114711a1929e6ee6f80233ec60907c0 Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Wed, 18 Feb 2015 12:33:30 +0100 Subject: [PATCH 05/13] new scene files --- .../linux/apps/raspicam/gl_scenes/shader.c | 287 ++++++++++++++++++ .../linux/apps/raspicam/gl_scenes/shader.h | 41 +++ 2 files changed, 328 insertions(+) create mode 100644 host_applications/linux/apps/raspicam/gl_scenes/shader.c create mode 100644 host_applications/linux/apps/raspicam/gl_scenes/shader.h diff --git a/host_applications/linux/apps/raspicam/gl_scenes/shader.c b/host_applications/linux/apps/raspicam/gl_scenes/shader.c new file mode 100644 index 000000000..de7117541 --- /dev/null +++ b/host_applications/linux/apps/raspicam/gl_scenes/shader.c @@ -0,0 +1,287 @@ +/* +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, Tim Gover +Copyright (c) 2015, Antoine Villeret +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include "RaspiTexUtil.h" + +/* Vertex co-ordinates: + * + * v0----v1 + * | | + * | | + * | | + * v3----v2 + */ + +static const GLfloat vertices[] = +{ +#define V0 -0.8, 0.8, 0.8, +#define V1 0.8, 0.8, 0.8, +#define V2 0.8, -0.8, 0.8, +#define V3 -0.8, -0.8, 0.8, + V0 V3 V2 V2 V1 V0 +}; + +/* Texture co-ordinates: + * + * (0,0) b--c + * | | + * a--d + * + * b,a,d d,c,b + */ +static const GLfloat tex_coords[] = +{ + 0, 0, 0, 1, 1, 1, + 1, 1, 1, 0, 0, 0 +}; + +RASPITEXUTIL_SHADER_PROGRAM_T shader; + +static int shader_init(RASPITEX_STATE *state) +{ + int rc = raspitexutil_gl_init_2_0(state); + if (rc != 0) + goto end; + + rc = raspitexutil_build_shader_program(&shader); +end: + return rc; +} + +static int shader_update_shader(RASPITEX_STATE *state) +{ + int i; + + RASPITEXUTIL_SHADER_PARAMETER_T *array = shader.uniform_array; + + for(i=0; i 0) + { + switch (array[i].type) + { + /* float vectors */ + case GL_FLOAT: + glUniform1f( array[i].loc, array[i].param[0] ); + break; + case GL_FLOAT_VEC2: + glUniform2f( array[i].loc, (array[i].param[0]), (array[i].param[1]) ); + break; + case GL_FLOAT_VEC3: + glUniform3f( array[i].loc, (array[i].param[0]), (array[i].param[1]), + (array[i].param[2]) ); + break; + case GL_FLOAT_VEC4: + glUniform4f( array[i].loc, (array[i].param[0]), (array[i].param[1]), + (array[i].param[2]), (array[i].param[3]) ); + break; + /* int vectors */ + case GL_INT: + glUniform1i( array[i].loc, (array[i].param[0]) ); + break; + case GL_INT_VEC2: + glUniform2i( array[i].loc, (array[i].param[0]), (array[i].param[1]) ); + break; + case GL_INT_VEC3: + glUniform3i(array[i].loc, + (array[i].param[0]), (array[i].param[1]), (array[i].param[2]) ); + break; + case GL_INT_VEC4: + glUniform4i(array[i].loc, + (array[i].param[0]), (array[i].param[1]), + (array[i].param[2]), (array[i].param[3]) ); + break; + /* bool vectors */ + case GL_BOOL: + glUniform1f( array[i].loc, (array[i].param[0]) ); + break; + case GL_BOOL_VEC2: + glUniform2f( array[i].loc, (array[i].param[0]), (array[i].param[1]) ); + break; + case GL_BOOL_VEC3: + glUniform3f( array[i].loc, + (array[i].param[0]), (array[i].param[1]), + (array[i].param[2]) ); + break; + case GL_BOOL_VEC4: + glUniform4f( array[i].loc, + (array[i].param[0]), (array[i].param[1]), + (array[i].param[2]), (array[i].param[3]) ); + break; + + /* float matrices */ + case GL_FLOAT_MAT2: + // GL_TRUE = row major order, GL_FALSE = column major + glUniformMatrix2fv( array[i].loc, 1, GL_FALSE, array[i].param ); + break; + case GL_FLOAT_MAT3: + glUniformMatrix3fv( array[i].loc, 1, GL_FALSE, array[i].param ); + break; + case GL_FLOAT_MAT4: + glUniformMatrix4fv( array[i].loc, 1, GL_FALSE, array[i].param ); + break; + + /* textures */ + case GL_SAMPLER_2D: + glUniform1i(array[i].loc, array[i].param[0]); + break; + case GL_SAMPLER_CUBE: break; + glUniform1i(array[i].loc, (array[i].param[0])); + break; + default: + ; + } + // remove flag because the value is in GL's state now... + array[i].flag=0; + + } + } + return 0; +} + +static int shader_redraw(RASPITEX_STATE *state) +{ + // Start with a clear screen + //~ static float offset = 0.0; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Bind the OES texture which is used to render the camera preview + glBindTexture(GL_TEXTURE_EXTERNAL_OES, state->texture); + + //~ offset += 0.05; + GLCHK(glUseProgram(shader.program)); + GLCHK(glEnableVertexAttribArray(shader.attribute_locations[0])); + GLfloat varray[] = { + -1.0f, -1.0f, + 1.0f, 1.0f, + 1.0f, -1.0f, + + -1.0f, 1.0f, + 1.0f, 1.0f, + -1.0f, -1.0f, + }; + GLCHK(glVertexAttribPointer(shader.attribute_locations[0], 2, GL_FLOAT, GL_FALSE, 0, varray)); + + shader_update_shader(state); + + //GLCHK(glUniform1f(shader.uniform_locations[1], offset)); + GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6)); + + GLCHK(glDisableVertexAttribArray(shader.attribute_locations[0])); + GLCHK(glUseProgram(0)); + return 0; +} + +int shader_open(RASPITEX_STATE *state) +{ + const GLchar *defaultVertexShader = + "attribute vec2 vertex;\n" + "varying vec2 texcoord;" + "void main(void) {\n" + " texcoord = 0.5 * (vertex + 1.0);\n" + " gl_Position = vec4(vertex, 0.0, 1.0);\n" + "}\n"; + + const GLchar *defaultFragmentShader = + "#extension GL_OES_EGL_image_external : require\n" + "varying vec2 texcoord;" + "uniform samplerExternalOES tex;" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D(tex, texcoord); \n" + "} \n"; + + FILE * pfFile=NULL; + FILE * pvFile=NULL; + long lSize; + int result; + + pfFile = fopen (state->fragment_shader_filename,"rb"); + if (pfFile==NULL) { + printf("No or invalid fragment file provided, used the default one\n"); + shader.fragment_source=defaultFragmentShader; + } else { + + // obtain file size: + fseek (pfFile , 0 , SEEK_END); + lSize = ftell (pfFile); + rewind (pfFile); + + // allocate memory to contain the whole file: + shader.fragment_source = (GLchar*) malloc (sizeof(GLchar)*lSize); + if (shader.fragment_source == NULL) {fputs ("Memory error",stderr); exit (2);} + + // copy the file into the buffer: + result = fread (shader.fragment_source,1,lSize,pfFile); + if (result != lSize) {fputs ("Reading error",stderr); exit (3);} + + printf("fragment shader file : %s\n", state->fragment_shader_filename); + + /* the whole file is now loaded in the memory buffer. */ + } + + pvFile = fopen (state->vertex_shader_filename,"rb"); + if (pvFile==NULL) { + printf("No or invalid vertex file provided, used the default one\n"); + shader.vertex_source=defaultVertexShader; + } else { + + // obtain file size: + fseek (pvFile , 0 , SEEK_END); + lSize = ftell (pvFile); + rewind (pvFile); + + // allocate memory to contain the whole file: + shader.vertex_source = (GLchar*) malloc (sizeof(GLchar)*lSize); + if (shader.vertex_source == NULL) {fputs ("Memory error",stderr); exit (2);} + + // copy the file into the buffer: + result = fread (shader.vertex_source,1,lSize,pvFile); + if (result != lSize) {fputs ("Reading error",stderr); exit (3);} + + printf("vertex shader file : %s\n", state->vertex_shader_filename); + + /* the whole file is now loaded in the memory buffer. */ + } + + state->ops.gl_init = shader_init; + state->ops.redraw = shader_redraw; + state->ops.update_texture = raspitexutil_update_texture; + return 0; +} + +RASPITEXUTIL_SHADER_PROGRAM_T* shader_get_shader() +{ + return &shader; +} diff --git a/host_applications/linux/apps/raspicam/gl_scenes/shader.h b/host_applications/linux/apps/raspicam/gl_scenes/shader.h new file mode 100644 index 000000000..56fb9089e --- /dev/null +++ b/host_applications/linux/apps/raspicam/gl_scenes/shader.h @@ -0,0 +1,41 @@ +/* +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, Tim Gover +Copyright (c) 2015, Antoine Villeret + +All rights reserved. + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SHADER_H +#define SHADER_H + +#include "RaspiTex.h" +#include "RaspiTexUtil.h" + +int shader_open(RASPITEX_STATE *state); +RASPITEXUTIL_SHADER_PROGRAM_T* oscshader_get_shader(); + +#endif /* SHADER_H */ From 529f4cfbb0baf536728c9c01b3a8804a96020487 Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Wed, 18 Feb 2015 13:00:55 +0100 Subject: [PATCH 06/13] add OSC support --- .../linux/apps/raspicam/RaspiStill.c | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/host_applications/linux/apps/raspicam/RaspiStill.c b/host_applications/linux/apps/raspicam/RaspiStill.c index ca4e452c5..5fa8719d2 100644 --- a/host_applications/linux/apps/raspicam/RaspiStill.c +++ b/host_applications/linux/apps/raspicam/RaspiStill.c @@ -79,6 +79,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "gl_scenes/shader.h" + +#ifdef HAVE_LIBLO +#include +#endif + // Standard port setting for the camera component #define MMAL_CAMERA_PREVIEW_PORT 0 #define MMAL_CAMERA_VIDEO_PORT 1 @@ -151,6 +156,12 @@ typedef struct MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port RASPITEX_STATE raspitex_state; /// GL renderer state and parameters + + #ifdef HAVE_LIBLO + lo_server_thread osc_server; + char* osc_inport; + #endif + int useOSC; } RASPISTILL_STATE; @@ -190,6 +201,7 @@ static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag); #define CommandCamSelect 20 #define CommandBurstMode 21 #define CommandSensorMode 22 +#define CommandOSCport 23 #define CommandFragmentShader 24 #define CommandVertexShader 25 @@ -218,6 +230,7 @@ static COMMAND_LIST cmdline_commands[] = { CommandCamSelect, "-camselect","cs", "Select camera . Default 0", 1 }, { CommandBurstMode, "-burst", "bm", "Enable 'burst capture mode'", 0}, { CommandSensorMode,"-mode", "md", "Force sensor mode. 0=auto. See docs for other modes available", 1}, + { CommandOSCport, "-oscport", "oscp", "OSC input port", 1 }, { CommandFragmentShader, "-fragmentshader", "frag", "fragment shader program file", 1 }, { CommandVertexShader, "-fragmentshader", "vert", "vertex shader program file", 1 }, }; @@ -299,6 +312,8 @@ static void default_status(RASPISTILL_STATE *state) state->cameraNum = 0; state->burstCaptureMode=0; state->sensor_mode = 0; + + state->useOSC = 0; // Setup preview window defaults raspipreview_set_defaults(&state->preview_parameters); @@ -308,6 +323,7 @@ static void default_status(RASPISTILL_STATE *state) // Set initial GL preview state raspitex_set_defaults(&state->raspitex_state); + } /** @@ -644,6 +660,7 @@ static int parse_cmdline(int argc, const char **argv, RASPISTILL_STATE *state) case CommandOSCport: // Set OSC port (only valid with shader scene) { +#ifdef HAVE_LIBLO int len = strlen(argv[i + 1]); if (len) { @@ -657,6 +674,10 @@ static int parse_cmdline(int argc, const char **argv, RASPISTILL_STATE *state) else valid = 0; break; +#else + fprintf(stderr, "OSC port passed as argument put Raspistill have been build without liblo !"); + fprintf(stderr, "OSC is disable."); +#endif /* HAVE_LIBLO */ } case CommandFragmentShader: // Set fragment shader file to load @@ -1664,6 +1685,54 @@ static void rename_file(RASPISTILL_STATE *state, FILE *output_file, } } +#ifdef HAVE_LIBLO +void osc_error(int num, const char *msg, const char *path) +{ + printf("liblo server error %d in path %s: %s\n", num, path, msg); + fflush(stdout); +} + +void osc_generic_handler(const char *path, const char *types, lo_arg ** argv, + int argc, void *data, void *user_data) +{ + int i; + + RASPISTILL_STATE *state = user_data; + RASPITEXUTIL_SHADER_PROGRAM_T *shader = shader_get_shader(); + + if (state->verbose) + { + fprintf(stderr, "Receive OSC message : %s with %d values\n", path, argc); + } + + for (i=0;iuniform_count;i++){ + if ( strcmp(shader->uniform_array[i].name, path+1) == 0 ){ + int j; + for (j=0;juniform_array[i].param[j]= (GLfloat) argv[j]->f; + } else if ( types[j] == 'i' ){ + shader->uniform_array[i].param[j]= (GLfloat) argv[j]->i; + } else { + printf("%s parameter #%d wrong type (%c)! only float or int are allowed !\n",path,j,types[j]); + } + } + shader->uniform_array[i].flag = 1; + break; + } + } +} + +static void init_osc(RASPISTILL_STATE *state) +{ + printf("initialize OSC server on port %s\n", state->osc_inport); + state->osc_server = lo_server_thread_new(state->osc_inport, osc_error); + /* add method that will match any path and args */ + lo_server_thread_add_method(state->osc_server , NULL, NULL, (lo_method_handler) osc_generic_handler, state); + lo_server_thread_start(state->osc_server); +} +#endif /* HAVE_LIBLO */ + /** * main */ @@ -1718,6 +1787,11 @@ int main(int argc, const char **argv) if (state.useGL) raspitex_init(&state.raspitex_state); +#ifdef HAVE_LIBLO + if (state.useOSC) + init_osc(&state); +#endif + // OK, we have a nice set of parameters. Now set up our components // We have three components. Camera, Preview and encoder. // Camera and encoder are different in stills/video, but preview From 8e4a0fd96191a4fe2dc9c62ee3551302d2074e3b Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Wed, 18 Feb 2015 13:01:31 +0100 Subject: [PATCH 07/13] try to detect liblo automatically this doesn't seem to work for cross-compiling yet --- .../linux/apps/raspicam/CMakeLists.txt | 10 ++- makefiles/cmake/Modules/Findliblo.cmake | 68 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 makefiles/cmake/Modules/Findliblo.cmake diff --git a/host_applications/linux/apps/raspicam/CMakeLists.txt b/host_applications/linux/apps/raspicam/CMakeLists.txt index fca8a8063..c9158b0ac 100644 --- a/host_applications/linux/apps/raspicam/CMakeLists.txt +++ b/host_applications/linux/apps/raspicam/CMakeLists.txt @@ -3,6 +3,8 @@ SET(COMPILE_DEFINITIONS -Werror) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/makefiles/cmake/Modules/") + include_directories(${PROJECT_SOURCE_DIR}/host_applications/linux/libs/bcm_host/include) include_directories(${PROJECT_SOURCE_DIR}/host_applications/linux/apps/raspicam/) @@ -27,7 +29,13 @@ add_executable(raspividyuv ${COMMON_SOURCES} RaspiVidYUV.c) set (MMAL_LIBS mmal_core mmal_util mmal_vc_client) -target_link_libraries(raspistill ${MMAL_LIBS} vcos bcm_host GLESv2 EGL m) +find_package(liblo) +include_directories(${liblo_INCLUDE_DIRS}) +if(liblo_FOUND) + add_definitions(HAVE_LIBLO) +endif() + +target_link_libraries(raspistill ${MMAL_LIBS} vcos bcm_host GLESv2 EGL m ${liblo_LIBRARIES}) target_link_libraries(raspiyuv ${MMAL_LIBS} vcos bcm_host) target_link_libraries(raspivid ${MMAL_LIBS} vcos bcm_host) target_link_libraries(raspividyuv ${MMAL_LIBS} vcos bcm_host) diff --git a/makefiles/cmake/Modules/Findliblo.cmake b/makefiles/cmake/Modules/Findliblo.cmake new file mode 100644 index 000000000..36082e435 --- /dev/null +++ b/makefiles/cmake/Modules/Findliblo.cmake @@ -0,0 +1,68 @@ +# - Try to find liblo +# Once done this will define +# +# LIBLO_FOUND - system has liblo +# LIBLO_INCLUDE_DIRS - the liblo include directory +# LIBLO_LIBRARIES - Link these to use liblo +# LIBLO_DEFINITIONS - Compiler switches required for using liblo +# +# Adapted from cmake-modules Google Code project +# +# Copyright (c) 2006 Andreas Schneider +# +# (Changes for liblo) Copyright (c) 2008 Kyle Machulis +# +# Redistribution and use is allowed according to the terms of the New BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +if (LIBLO_LIBRARIES AND LIBLO_INCLUDE_DIRS) + # in cache already + set(LIBLO_FOUND TRUE) +else (LIBLO_LIBRARIES AND LIBLO_INCLUDE_DIRS) + find_path(LIBLO_INCLUDE_DIR + NAMES + lo/lo.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ) + + find_library(LIBLO_LIBRARY + NAMES + lo + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ) + + set(LIBLO_INCLUDE_DIRS + ${LIBLO_INCLUDE_DIR} + ) + set(LIBLO_LIBRARIES + ${LIBLO_LIBRARY} +) + + if (LIBLO_INCLUDE_DIRS AND LIBLO_LIBRARIES) + set(LIBLO_FOUND TRUE) + endif (LIBLO_INCLUDE_DIRS AND LIBLO_LIBRARIES) + + if (LIBLO_FOUND) + if (NOT liblo_FIND_QUIETLY) + message(STATUS "Found liblo: ${LIBLO_LIBRARIES}") + endif (NOT liblo_FIND_QUIETLY) + else (LIBLO_FOUND) + if (liblo_FIND_REQUIRED) + message(FATAL_ERROR "Could not find liblo") + endif (liblo_FIND_REQUIRED) + endif (LIBLO_FOUND) + + # show the LIBLO_INCLUDE_DIRS and LIBLO_LIBRARIES variables only in the advanced view + mark_as_advanced(LIBLO_INCLUDE_DIRS LIBLO_LIBRARIES) + +endif (LIBLO_LIBRARIES AND LIBLO_INCLUDE_DIRS) From 8809f9fd842a7e3af2d71d760c55b6dab758c0a5 Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Wed, 18 Feb 2015 13:04:22 +0100 Subject: [PATCH 08/13] do not redefined VCOS_LOG_CATEGORY don't fully understand all the consequences of this... --- host_applications/linux/apps/raspicam/RaspiTexUtil.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/host_applications/linux/apps/raspicam/RaspiTexUtil.h b/host_applications/linux/apps/raspicam/RaspiTexUtil.h index 3ff3e21d1..618e003e9 100644 --- a/host_applications/linux/apps/raspicam/RaspiTexUtil.h +++ b/host_applications/linux/apps/raspicam/RaspiTexUtil.h @@ -29,7 +29,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef RASPITEX_UTIL_H_ #define RASPITEX_UTIL_H_ +#ifndef VCOS_LOG_CATEGORY #define VCOS_LOG_CATEGORY (&raspitex_log_category) +#endif #include #include #include From 0f78260a0cb6a68186d6d41b7c39910772f4782a Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Wed, 18 Feb 2015 17:04:09 +0100 Subject: [PATCH 09/13] fix typo --- host_applications/linux/apps/raspicam/CMakeLists.txt | 11 ++++++----- .../linux/apps/raspicam/gl_scenes/shader.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/host_applications/linux/apps/raspicam/CMakeLists.txt b/host_applications/linux/apps/raspicam/CMakeLists.txt index c9158b0ac..ed625e71e 100644 --- a/host_applications/linux/apps/raspicam/CMakeLists.txt +++ b/host_applications/linux/apps/raspicam/CMakeLists.txt @@ -29,13 +29,14 @@ add_executable(raspividyuv ${COMMON_SOURCES} RaspiVidYUV.c) set (MMAL_LIBS mmal_core mmal_util mmal_vc_client) -find_package(liblo) -include_directories(${liblo_INCLUDE_DIRS}) -if(liblo_FOUND) - add_definitions(HAVE_LIBLO) +FIND_PACKAGE(liblo) +include_directories(${LIBLO_INCLUDE_DIRS}) +if(LIBLO_FOUND) + message( STATUS "Building with OSC support !") + add_definitions(-DHAVE_LIBLO) endif() -target_link_libraries(raspistill ${MMAL_LIBS} vcos bcm_host GLESv2 EGL m ${liblo_LIBRARIES}) +target_link_libraries(raspistill ${MMAL_LIBS} vcos bcm_host GLESv2 EGL m ${LIBLO_LIBRARIES}) target_link_libraries(raspiyuv ${MMAL_LIBS} vcos bcm_host) target_link_libraries(raspivid ${MMAL_LIBS} vcos bcm_host) target_link_libraries(raspividyuv ${MMAL_LIBS} vcos bcm_host) diff --git a/host_applications/linux/apps/raspicam/gl_scenes/shader.h b/host_applications/linux/apps/raspicam/gl_scenes/shader.h index 56fb9089e..7f9c90312 100644 --- a/host_applications/linux/apps/raspicam/gl_scenes/shader.h +++ b/host_applications/linux/apps/raspicam/gl_scenes/shader.h @@ -36,6 +36,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "RaspiTexUtil.h" int shader_open(RASPITEX_STATE *state); -RASPITEXUTIL_SHADER_PROGRAM_T* oscshader_get_shader(); +RASPITEXUTIL_SHADER_PROGRAM_T* shader_get_shader(); #endif /* SHADER_H */ From 635d169ce93a99b8647fa04943cc074fd15c8c36 Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Wed, 18 Feb 2015 17:09:29 +0100 Subject: [PATCH 10/13] add some tips to cross-compile with liblo --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 358d2b4bc..bbdd14cc4 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,15 @@ EGL, mmal, GLESv2, vcos, openmaxil, vchiq_arm, bcm_host, WFC, OpenVG. Use buildme to build. It requires cmake to be installed and an arm cross compiler. It is set up to use this one: https://github.com/raspberrypi/tools/tree/master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian + +Raspistill can be controlled through OpenSoundControl. +To enable that, you need liblo-dev package. +`sudo apt-get install liblo7 liblo-dev` +Install it and run ./buildme to build raspistill with OSC support. +Then you can control each shader parameters with OSC message. + +To cross-compile with liblo support, you can download deb package on your pi with this command : +`apt-get download liblo7 liblo-dev` +Then extract them in the folder returned by : `arm-linux-gnueabihf-gcc -print-sysroot`. + + From e52509a6c59532a488a40460adf93e742a913330 Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Mon, 23 Feb 2015 19:10:20 +0100 Subject: [PATCH 11/13] add a OFF parameter for exposure setting don't know if it is a good idea since the image is black with this setting --- host_applications/linux/apps/raspicam/RaspiCamControl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/host_applications/linux/apps/raspicam/RaspiCamControl.c b/host_applications/linux/apps/raspicam/RaspiCamControl.c index 62573c84a..923682824 100755 --- a/host_applications/linux/apps/raspicam/RaspiCamControl.c +++ b/host_applications/linux/apps/raspicam/RaspiCamControl.c @@ -44,6 +44,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// Structure to cross reference exposure strings against the MMAL parameter equivalent static XREF_T exposure_map[] = { + {"off", MMAL_PARAM_EXPOSUREMODE_OFF}, {"auto", MMAL_PARAM_EXPOSUREMODE_AUTO}, {"night", MMAL_PARAM_EXPOSUREMODE_NIGHT}, {"nightpreview", MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW}, From fe627e06f33dfcdf95ebc38ad4835ccb93bea53c Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Tue, 29 Nov 2016 20:23:32 +0100 Subject: [PATCH 12/13] some changes according to @timgover review --- .../linux/apps/raspicam/RaspiTexUtil.c | 2 -- .../linux/apps/raspicam/gl_scenes/shader.c | 20 +++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/host_applications/linux/apps/raspicam/RaspiTexUtil.c b/host_applications/linux/apps/raspicam/RaspiTexUtil.c index 269a70898..b4435aa9b 100644 --- a/host_applications/linux/apps/raspicam/RaspiTexUtil.c +++ b/host_applications/linux/apps/raspicam/RaspiTexUtil.c @@ -630,7 +630,6 @@ void raspitexutil_create_param_array(RASPITEXUTIL_SHADER_PROGRAM_T *p) array[i].size = 0; array[i].type = 0; array[i].loc = 0; - // uniform_array[i].param = (float*) malloc(sizeof(float)*16); array[i].name = (GLchar*) malloc(sizeof(GLchar)* p->max_length+1);; array[i].flag = 0; for(j=0; j<16; j++)array[i].param[j]=0; @@ -642,7 +641,6 @@ void raspitexutil_create_param_array(RASPITEXUTIL_SHADER_PROGRAM_T *p) array[i].size = 0; array[i].type = 0; array[i].loc = 0; - // attribute_array[i].param = (float*) malloc(sizeof(float)*16); array[i].name = (GLchar*) malloc(sizeof(GLchar)* p->max_length+1); array[i].flag = 0; for(j=0; j<16; j++)array[i].param[j]=0; diff --git a/host_applications/linux/apps/raspicam/gl_scenes/shader.c b/host_applications/linux/apps/raspicam/gl_scenes/shader.c index de7117541..ed340fffc 100644 --- a/host_applications/linux/apps/raspicam/gl_scenes/shader.c +++ b/host_applications/linux/apps/raspicam/gl_scenes/shader.c @@ -229,7 +229,7 @@ int shader_open(RASPITEX_STATE *state) pfFile = fopen (state->fragment_shader_filename,"rb"); if (pfFile==NULL) { - printf("No or invalid fragment file provided, used the default one\n"); + fprintf(stderr,"No or invalid fragment file provided, used the default one\n"); shader.fragment_source=defaultFragmentShader; } else { @@ -240,12 +240,14 @@ int shader_open(RASPITEX_STATE *state) // allocate memory to contain the whole file: shader.fragment_source = (GLchar*) malloc (sizeof(GLchar)*lSize); - if (shader.fragment_source == NULL) {fputs ("Memory error",stderr); exit (2);} // copy the file into the buffer: result = fread (shader.fragment_source,1,lSize,pfFile); - if (result != lSize) {fputs ("Reading error",stderr); exit (3);} - + if (result != lSize) { + fputs ("Reading error",stderr); + return -1; + } + printf("fragment shader file : %s\n", state->fragment_shader_filename); /* the whole file is now loaded in the memory buffer. */ @@ -253,7 +255,7 @@ int shader_open(RASPITEX_STATE *state) pvFile = fopen (state->vertex_shader_filename,"rb"); if (pvFile==NULL) { - printf("No or invalid vertex file provided, used the default one\n"); + fprintf(stderr, "No or invalid vertex file provided, used the default one\n"); shader.vertex_source=defaultVertexShader; } else { @@ -264,12 +266,14 @@ int shader_open(RASPITEX_STATE *state) // allocate memory to contain the whole file: shader.vertex_source = (GLchar*) malloc (sizeof(GLchar)*lSize); - if (shader.vertex_source == NULL) {fputs ("Memory error",stderr); exit (2);} // copy the file into the buffer: result = fread (shader.vertex_source,1,lSize,pvFile); - if (result != lSize) {fputs ("Reading error",stderr); exit (3);} - + if (result != lSize) { + fputs ("Reading error",stderr); + return -1; + } + printf("vertex shader file : %s\n", state->vertex_shader_filename); /* the whole file is now loaded in the memory buffer. */ From ddd6a66b758ae823006d1a3dbf7bffb0eb5b898b Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Tue, 25 Dec 2018 19:24:05 +0100 Subject: [PATCH 13/13] fix build --- host_applications/linux/apps/raspicam/CMakeLists.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/host_applications/linux/apps/raspicam/CMakeLists.txt b/host_applications/linux/apps/raspicam/CMakeLists.txt index 4ef655cb1..e7bd98da0 100644 --- a/host_applications/linux/apps/raspicam/CMakeLists.txt +++ b/host_applications/linux/apps/raspicam/CMakeLists.txt @@ -32,15 +32,14 @@ add_executable(raspividyuv ${COMMON_SOURCES} RaspiVidYUV.c) set (MMAL_LIBS mmal_core mmal_util mmal_vc_client) FIND_PACKAGE(liblo) -set (FOUND_LIBLO_LIBRARY) -include_directories(${LIBLO_INCLUDE_DIRS}) if(LIBLO_FOUND) message( STATUS "Building with OSC support !") add_definitions(-DHAVE_LIBLO) - SET(FOUND_LIBLO_LIBRARY ${LIBLO_LIBRARIES}) + include_directories(${LIBLO_INCLUDE_DIRS}) + target_link_libraries(raspistill ${LIBLO_LIBRARIES}) endif() -target_link_libraries(raspistill ${MMAL_LIBS} vcos bcm_host GLESv2 EGL m ${FOUND_LIBLO_LIBRARY}) +target_link_libraries(raspistill ${MMAL_LIBS} vcos bcm_host GLESv2 EGL m) target_link_libraries(raspiyuv ${MMAL_LIBS} vcos bcm_host) target_link_libraries(raspivid ${MMAL_LIBS} vcos bcm_host) target_link_libraries(raspividyuv ${MMAL_LIBS} vcos bcm_host)