1
0
mirror of https://github.com/danog/Telegram.git synced 2025-01-06 04:58:56 +01:00
Telegram/thirdparty/RMIntro/core/objects.c
2015-10-01 19:19:52 +03:00

1306 lines
38 KiB
C

//
// objects.c
// IntroOpenGL
//
// Created by Ilya Rimchikov on 29/03/14.
// Copyright (c) 2014 IntroOpenGL. All rights reserved.
//
#include "objects.h"
#include "buffer.h"
#include "platform_gl.h"
#include "program.h"
#include "shader.h"
#include "linmath.h"
#include "matrix.h"
#include "math_helper.h"
#include "platform_log.h"
#include <math.h>
#include <stdlib.h>
#include "animations.h"
float scale_factor;
int width, height;
int y_offset_absolute;
static TextureProgram texture_program;
static TextureProgram texture_program_one;
static TextureProgram texture_program_red;
static TextureProgram texture_program_blue;
static TextureProgram texture_program_light_red;
static TextureProgram texture_program_light_blue;
static TextureProgram *texture_program_temp;
static ColorProgram color_program;
static GradientProgram gradient_program;
static float y_offset;
void set_y_offset_objects(float a)
{
y_offset = a;
}
void setup_shaders()
{
char *vshader =
"uniform mat4 u_MvpMatrix;"
"attribute vec4 a_Position;"
"void main(){"
" gl_Position = u_MvpMatrix * a_Position;"
"}";
char *fshader =
"precision lowp float;"
"uniform vec4 u_Color;"
"uniform float u_Alpha;"
"void main() {"
" gl_FragColor = u_Color;"
//" gl_FragColor = vec4(0,1,0,1);"
" gl_FragColor.w*=u_Alpha;"
"}";
color_program = get_color_program(build_program(vshader, (GLint)strlen(vshader), fshader, (GLint)strlen(fshader)));
char *vertex_gradient_shader =
"uniform mat4 u_MvpMatrix;"
"attribute vec4 a_Position;"
"attribute vec4 a_Color;"
"varying vec4 v_DestinationColor;"
"void main(){"
" v_DestinationColor = a_Color;"
" gl_Position = u_MvpMatrix * a_Position;"
"}";
char *fragment_gradient_shader =
"precision lowp float;"
"uniform float u_Alpha;"
"varying vec4 v_DestinationColor;"
"void main() {"
" gl_FragColor = v_DestinationColor;"
" gl_FragColor.w*=u_Alpha;"
//" gl_FragColor = vec4(0,1,0,1);"
"}";
gradient_program = get_gradient_program(build_program(vertex_gradient_shader, (GLint)strlen(vertex_gradient_shader), fragment_gradient_shader, (GLint)strlen(fragment_gradient_shader)));
char* vshader_texture =
"uniform mat4 u_MvpMatrix;"
"attribute vec4 a_Position;"
"attribute vec2 a_TextureCoordinates;"
"varying vec2 v_TextureCoordinates;"
"void main(){"
" v_TextureCoordinates = a_TextureCoordinates;"
" gl_Position = u_MvpMatrix * a_Position;"
"}";
char* fshader_texture =
"precision lowp float;"
"uniform sampler2D u_TextureUnit;"
"varying vec2 v_TextureCoordinates;"
"uniform float u_Alpha;"
"void main(){"
" gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);"
" gl_FragColor.w *= u_Alpha;"
"}";
texture_program = get_texture_program(build_program(vshader_texture, (GLint)strlen(vshader_texture), fshader_texture, (GLint)strlen(fshader_texture)));
char* vshader_texture_blue =
"uniform mat4 u_MvpMatrix;"
"attribute vec4 a_Position;"
"attribute vec2 a_TextureCoordinates;"
"varying vec2 v_TextureCoordinates;"
"void main(){"
" v_TextureCoordinates = a_TextureCoordinates;"
" gl_Position = u_MvpMatrix * a_Position;"
"}";
char* fshader_texture_blue =
"precision lowp float;"
"uniform sampler2D u_TextureUnit;"
"varying vec2 v_TextureCoordinates;"
"uniform float u_Alpha;"
"void main(){"
" gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);"
//" float p = u_Alpha*gl_FragColor.w*0.4;"
//" gl_FragColor = vec4(0,0.353,0.761,p);"
" float p = u_Alpha*gl_FragColor.w;"
" gl_FragColor = vec4(0,0.6,0.898,p);"
"}";
texture_program_blue = get_texture_program(build_program(vshader_texture_blue, (GLint)strlen(vshader_texture_blue), fshader_texture_blue, (GLint)strlen(fshader_texture_blue)));
char* vshader_texture_red =
"uniform mat4 u_MvpMatrix;"
"attribute vec4 a_Position;"
"attribute vec2 a_TextureCoordinates;"
"varying vec2 v_TextureCoordinates;"
"void main(){"
" v_TextureCoordinates = a_TextureCoordinates;"
" gl_Position = u_MvpMatrix * a_Position;"
"}";
char* fshader_texture_red =
"precision lowp float;"
"uniform sampler2D u_TextureUnit;"
"varying vec2 v_TextureCoordinates;"
"uniform float u_Alpha;"
"void main(){"
" gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);"
//" float p = gl_FragColor.w*0.45*u_Alpha;"
//" gl_FragColor = vec4(0.722,0.035,0,p);"
" float p = gl_FragColor.w*u_Alpha;"
" gl_FragColor = vec4(210./255.,57./255.,41./255.,p);"
"}";
texture_program_red = get_texture_program(build_program(vshader_texture_red, (GLint)strlen(vshader_texture_red), fshader_texture_red, (GLint)strlen(fshader_texture_red)));
vshader =
"uniform mat4 u_MvpMatrix;"
"attribute vec4 a_Position;"
"attribute vec2 a_TextureCoordinates;"
"varying vec2 v_TextureCoordinates;"
"void main(){"
" v_TextureCoordinates = a_TextureCoordinates;"
" gl_Position = u_MvpMatrix * a_Position;"
"}";
fshader =
"precision lowp float;"
"uniform sampler2D u_TextureUnit;"
"varying vec2 v_TextureCoordinates;"
"uniform float u_Alpha;"
"void main(){"
" gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);"
//" float p = u_Alpha*gl_FragColor.w;"
//" gl_FragColor = vec4(237./255., 64./255., 27./255., p);"
" float p = u_Alpha*gl_FragColor.w;"
" gl_FragColor = vec4(246./255., 73./255., 55./255., p);"
"}";
texture_program_light_red = get_texture_program(build_program(vshader, (GLint)strlen(vshader), fshader, (GLint)strlen(fshader)));
vshader =
"uniform mat4 u_MvpMatrix;"
"attribute vec4 a_Position;"
"attribute vec2 a_TextureCoordinates;"
"varying vec2 v_TextureCoordinates;"
"void main(){"
" v_TextureCoordinates = a_TextureCoordinates;"
" gl_Position = u_MvpMatrix * a_Position;"
"}";
fshader =
"precision lowp float;"
"uniform sampler2D u_TextureUnit;"
"varying vec2 v_TextureCoordinates;"
"uniform float u_Alpha;"
"void main(){"
" gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);"
" float p = u_Alpha*gl_FragColor.w;"
//" gl_FragColor = vec4(100./255.,182./255.,248./255.,p);"
" gl_FragColor = vec4(42./255.,180./255.,247./255.,p);"
"}";
texture_program_light_blue = get_texture_program(build_program(vshader, (GLint)strlen(vshader), fshader, (GLint)strlen(fshader)));
vshader =
"uniform mat4 u_MvpMatrix;"
"attribute vec4 a_Position;"
"attribute vec2 a_TextureCoordinates;"
"varying vec2 v_TextureCoordinates;"
"void main(){"
" v_TextureCoordinates = a_TextureCoordinates;"
" gl_Position = u_MvpMatrix * a_Position;"
"}";
fshader =
"precision lowp float;"
"uniform sampler2D u_TextureUnit;"
"varying vec2 v_TextureCoordinates;"
"uniform float u_Alpha;"
"void main(){"
" gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);"
" gl_FragColor *= u_Alpha;"
"}";
texture_program_one = get_texture_program(build_program(vshader, (GLint)strlen(vshader), fshader, (GLint)strlen(fshader)));
}
CPoint CPointMake(float x, float y)
{
CPoint p = {x, y};
return p;
}
CSize CSizeMake(float width, float height)
{
CSize s = {width, height};
return s;
}
float D2R(float a)
{
return a*M_PI/180.0;
}
float R2D(float a)
{
return a*180.0/M_PI;
}
xyz xyzMake(float x, float y, float z) {
xyz result;
result.x = x;
result.y = y;
result.z = z;
return result;
}
LayerParams default_layer_params()
{
LayerParams params;
params.anchor.x=params.anchor.y=params.anchor.z=0;
params.position.x=params.position.y=params.position.z=0;
params.rotation=0;
params.scale.x=params.scale.y=params.scale.z=1.;
return params;
}
Params default_params()
{
Params params;
params.anchor.x=params.anchor.y=params.anchor.z=0;
params.position.x=params.position.y=params.position.z=0;
params.rotation=0;
params.scale.x=params.scale.y=params.scale.z=1.;
params.alpha=1.;
params.var_params.side_length=0;
params.var_params.start_angle=0;
params.var_params.end_angle=0;
params.var_params.angle=0;
params.var_params.size=CSizeMake(0, 0);
params.var_params.radius=0;
params.var_params.width=0;
params.const_params.is_star=0;
LayerParams p = default_layer_params();
params.layer_params=&p;
return params;
}
void mat4x4_translate_independed(mat4x4 m, float x, float y, float z)
{
mat4x4 tr;
mat4x4_identity(tr);
mat4x4_translate_in_place(tr, x, y, z);
//mat4x4 model_matrix2_tr;
//mat4x4_mul(model_matrix2_tr, tr, m);
mat4x4 m_dup;
mat4x4_dup(m_dup, m);
mat4x4_mul(m, tr, m_dup );
}
static inline void mvp_matrix(mat4x4 model_view_projection_matrix, Params params, mat4x4 view_projection_matrix)
{
mat4x4 model_matrix;
mat4x4_identity(model_matrix);
mat4x4 id;
mat4x4_identity(id);
mat4x4_translate(model_matrix, -params.anchor.x, -params.anchor.y, params.anchor.z);
mat4x4 scaled;
mat4x4_identity(scaled);
mat4x4_scale_aniso(scaled, scaled, params.scale.x, -params.scale.y, params.scale.z);
mat4x4 tmp;
mat4x4_dup(tmp, model_matrix);
mat4x4_mul(model_matrix, scaled, tmp);
mat4x4 rotate;
mat4x4_dup(rotate, id);
mat4x4_rotate_Z2(rotate, id, deg_to_radf(-params.rotation));
mat4x4_dup(tmp, model_matrix);
mat4x4_mul(model_matrix, rotate, tmp);
mat4x4_translate_independed(model_matrix, params.position.x, -params.position.y, params.position.z);
mat4x4 model_matrix3;
mat4x4_identity(model_matrix3);
mat4x4 mm;
mat4x4_mul(mm, model_matrix3, view_projection_matrix);
mat4x4_mul(model_view_projection_matrix, mm, model_matrix);
mat4x4_translate_independed(model_view_projection_matrix, 0, -y_offset/view_projection_matrix[3][3], 0);
}
void mat4x4_log(mat4x4 M)
{
/*
printf("\n\n");
int i, j;
for(i=0; i<4; ++i)
{
for(j=0; j<4; ++j)
{
printf("%6.2f ", M[i][j]);
}
printf("\n");
}
printf("\n\n");
*/
}
void vec4_log(vec4 M)
{
/*
printf("\n\n");
int i;
for(i=0; i<4; ++i)
{
printf("%6.2f ", M[i]);
}
printf("\n\n");
*/
}
void draw_shape(const Shape* shape, mat4x4 view_projection_matrix)
{
if (shape->params.alpha>0 && (fabs(shape->params.scale.x)>0 && fabs(shape->params.scale.y)>0 && fabs(shape->params.scale.z)>0))
{
mat4x4 model_view_projection_matrix;
mvp_matrix(model_view_projection_matrix, shape->params, view_projection_matrix);
glUseProgram(color_program.program);
glUniformMatrix4fv(color_program.u_mvp_matrix_location, 1, GL_FALSE, (GLfloat*)model_view_projection_matrix);
if (shape->params.rotation==5.) {
glUniform4fv(color_program.u_color_location, 1, shape->color);
}
else if (shape->params.rotation==10.)
{
vec4 col ={0,1,0,1};
glUniform4fv(color_program.u_color_location, 1, col);
//glUniform4fv(color_program.u_color_location, 1, shape->color);
}
else
{
glUniform4fv(color_program.u_color_location, 1, shape->color);
}
glUniform1f(color_program.u_alpha_loaction, shape->params.alpha);
glVertexAttribPointer(color_program.a_position_location, 2, GL_FLOAT, GL_FALSE, sizeof(CPoint), &shape->data[0].x);
glEnableVertexAttribArray(color_program.a_position_location);
glDrawArrays(shape->params.const_params.triangle_mode, 0, shape->num_points);
}
}
void draw_textured_shape(const TexturedShape* shape, mat4x4 view_projection_matrix, texture_program_type program_type)
{
if (shape->params.alpha>0 && (fabs(shape->params.scale.x)>0 && fabs(shape->params.scale.y)>0 && fabs(shape->params.scale.z)>0))
{
mat4x4 model_view_projection_matrix;
mvp_matrix(model_view_projection_matrix, shape->params, view_projection_matrix);
if (shape->params.const_params.is_star==1) {
vec4 pos;
vec4 vertex = {0,0,0,1};
mat4x4_mul_vec4(pos, model_view_projection_matrix, vertex);
vec4 p_NDC = {pos[0]/pos[3], pos[1]/pos[3], pos[2]/pos[3], pos[3]/pos[3]};
// p_window = (p_NDC + 1)/2 * viewport.{width, height} + viewport{x, y}
//vec4 p_window={p_NDC[0]*width, -p_NDC[1]*height, 0, 0};
vec4 p_window={p_NDC[0]*width, -p_NDC[1]*height, 0, 0};
int d = 160;
if (fabs(p_window[0])>d || p_window[1] > y_offset_absolute*2 + d || p_window[1] < y_offset_absolute*2 - d) {
return;
}
}
if (program_type==RED) {
texture_program_temp=&texture_program_red;
}
else if (program_type==BLUE)
{
texture_program_temp=&texture_program_blue;
}
else if (program_type==LIGHT_RED)
{
texture_program_temp=&texture_program_light_red;
}
else if (program_type==LIGHT_BLUE)
{
texture_program_temp=&texture_program_light_blue;
}
else if (program_type==NORMAL_ONE)
{
texture_program_temp=&texture_program_one;
}
else
{
texture_program_temp=&texture_program;
}
glUseProgram(texture_program_temp->program);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, shape->texture);
glUniformMatrix4fv(texture_program_temp->u_mvp_matrix_location, 1, GL_FALSE, (GLfloat*)model_view_projection_matrix);
glUniform1i(texture_program_temp->u_texture_unit_location, 0);
glUniform1f(texture_program_temp->u_alpha_loaction, shape->params.alpha);
glBindBuffer(GL_ARRAY_BUFFER, shape->buffer);
// glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
glVertexAttribPointer(texture_program_temp->a_position_location, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GL_FLOAT), BUFFER_OFFSET(0));
glVertexAttribPointer(texture_program_temp->a_texture_coordinates_location, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GL_FLOAT), BUFFER_OFFSET(2 * sizeof(GL_FLOAT)));
glEnableVertexAttribArray(texture_program_temp->a_position_location);
glEnableVertexAttribArray(texture_program_temp->a_texture_coordinates_location);
glDrawArrays(shape->params.const_params.triangle_mode, 0, shape->num_points);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
// Rounded rectangle
static inline int size_of_rounded_rectangle_in_vertices(int round_count) {
return 4*(2+round_count)+2;
}
static inline void gen_rounded_rectangle(CPoint* out, CSize size, float radius, int round_count)
{
//printf("gen_rounded_rectangle> %d \n", round_count);
int offset=0;
out[offset++] = CPointMake(0, 0);
float k = M_PI/2/(round_count+1);
int i=0;
int n=0;
for (i=(round_count+2)*n; i<=round_count+1 + (round_count+1)*n; i++) {
out[offset++] = CPointMake(size.width/2-radius + cos(i*k)*radius, size.height/2-radius + sin(i*k)*radius);
}
n++;
for (i=(round_count+1)*n; i<=round_count+1 + (round_count+1)*n; i++) {
out[offset++] = CPointMake(-size.width/2+radius + cos(i*k)*radius, size.height/2-radius + sin(i*k)*radius);
}
n++;
for (i=(round_count+1)*n; i<=round_count+1 + (round_count+1)*n; i++) {
out[offset++] = CPointMake(-size.width/2+radius + cos(i*k)*radius, -size.height/2+radius + sin(i*k)*radius);
}
n++;
for (i=(round_count+1)*n; i<=round_count+1 + (round_count+1)*n; i++) {
out[offset++] = CPointMake(size.width/2-radius + cos(i*k)*radius, -size.height/2+radius + sin(i*k)*radius);
}
n++;
out[offset++] = CPointMake(size.width/2, size.height/2-radius);
}
Shape create_rounded_rectangle(CSize size, float radius, int round_count, const vec4 color)
{
int real_vertex_count = size_of_rounded_rectangle_in_vertices(round_count);
Params params = default_params();
params.const_params.datasize = sizeof(CPoint)*real_vertex_count*2;
params.const_params.round_count=round_count;
params.const_params.triangle_mode = GL_TRIANGLE_FAN;
params.var_params.size=size;
params.var_params.radius=radius;
CPoint *data = malloc(params.const_params.datasize);
gen_rounded_rectangle(data, params.var_params.size, params.var_params.radius, params.const_params.round_count);
/*
char str[150];
sprintf(str, "rounded_rectangle_data_size(%d) = %d", real_vertex_count, rounded_rectangle_data_size(real_vertex_count));
DEBUG_LOG_WRITE_D("fps>",str);
*/
return (Shape) {{color[0], color[1], color[2], color[3]},
data,
create_vbo(params.const_params.datasize, data, GL_DYNAMIC_DRAW),
real_vertex_count,
params};
}
void change_rounded_rectangle(Shape* shape, CSize size, float radius)
{
if ((*shape).params.var_params.size.width != size.width || (*shape).params.var_params.size.height != size.height || (*shape).params.var_params.radius != radius )
{
//DEBUG_LOG_WRITE_D("fps","change_rounded_rectangle");
(*shape).params.var_params.size.width = size.width;
(*shape).params.var_params.size.height = size.height;
(*shape).params.var_params.radius = radius;
gen_rounded_rectangle((*shape).data, (*shape).params.var_params.size, (*shape).params.var_params.radius, (*shape).params.const_params.round_count);
glBindBuffer(GL_ARRAY_BUFFER, shape->buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, shape->params.const_params.datasize, shape->data); // proved
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
// Segmented square
static inline int size_of_segmented_square_in_vertices() {
return 7;
}
static inline CPoint square_point(float angle, float radius)
{
CPoint p;
if (angle<=M_PI/2*.5 || angle>M_PI/2*3.5)
{
p = CPointMake(radius, radius * sin(angle)/cos(angle));
}
else if (angle<=M_PI/2*1.5)
{
p = CPointMake(radius * cos(angle)/sin(angle), radius);
}
else if (angle<=M_PI/2*2.5)
{
p = CPointMake(-radius, -radius * sin(angle)/cos(angle));
}
else if (angle<=M_PI/2*3.5)
{
p = CPointMake(-radius * cos(angle)/sin(angle), -radius);
}
return p;
}
static inline CPoint square_texture_point(CPoint p, float side_length)
{
return CPointMake((-p.x/side_length*.5 +.5), -p.y/side_length*.5 +.5);
}
static inline void gen_segmented_square(CPoint* out, float side_length, float start_angle, float end_angle)
{
CPoint p;
float radius = side_length;
int offset=0;
float k=1;
float da=D2R(-2.6*2)*k;
p = CPointMake(sin(start_angle+end_angle)*6*k, - cos(start_angle+end_angle)*6*k);
//p = CPointMake(0, 0);
out[offset++] = p;
out[offset++] = square_texture_point(p, side_length);
//1
p = square_point(start_angle+da, radius);
//p.y=p.y;
//p.y=side_length;
out[offset++] = p;
out[offset++] = square_texture_point(p, side_length);
int q=0;
int i;
for (i=start_angle; i<floor(R2D(start_angle+end_angle+da)); i++) {
if ((i+45)%90==0) {
p = square_point(D2R(i), radius);
out[offset++] = p;
out[offset++] = square_texture_point(p, side_length);
q++;
}
}
p = square_point(start_angle + end_angle+da, radius);
//p.x = p.x + sin(end_angle)*6*k;
//p.y = p.y - cos(end_angle)*6*k;
out[offset++] = p;
out[offset++] = square_texture_point(p, side_length);
for (i=0; i<4-q; i++) {
p = square_point(start_angle +end_angle+da, radius);
//p.x = p.x + sin(end_angle)*6*k;
//p.y = p.y - cos(end_angle)*6*k;
out[offset++] = p;
out[offset++] = square_texture_point(p, side_length);
}
}
TexturedShape create_segmented_square(float side_length, float start_angle, float end_angle, GLuint texture)
{
int real_vertex_count = size_of_segmented_square_in_vertices();
Params params = default_params();
params.const_params.datasize = sizeof(CPoint) * real_vertex_count * 2 * 2;
params.const_params.triangle_mode = GL_TRIANGLE_FAN;
CPoint *data = malloc(params.const_params.datasize);
gen_segmented_square(data, side_length, start_angle, end_angle);
return (TexturedShape) {texture,
data,
create_vbo(params.const_params.datasize, data, GL_DYNAMIC_DRAW),
real_vertex_count,
params};
}
void change_segmented_square(TexturedShape* shape, float side_length, float start_angle, float end_angle)
{
if ((*shape).params.var_params.side_length != side_length ||
(*shape).params.var_params.start_angle != start_angle ||
(*shape).params.var_params.end_angle != end_angle )
{
//DEBUG_LOG_WRITE_D("fps","change_segmented_square");
(*shape).params.var_params.side_length = side_length;
(*shape).params.var_params.start_angle = start_angle;
(*shape).params.var_params.end_angle = end_angle;
gen_segmented_square((*shape).data, side_length, start_angle, end_angle);
glBindBuffer(GL_ARRAY_BUFFER, shape->buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, shape->params.const_params.datasize, shape->data); // proved
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
// ok
// Rectangle
static inline void gen_rectangle(CPoint* out, CSize size)
{
int offset=0;
out[offset++] = CPointMake(-size.width/2, -size.height/2);
out[offset++] = CPointMake(size.width/2, -size.height/2);
out[offset++] = CPointMake(-size.width/2, size.height/2);
out[offset++] = CPointMake(size.width/2, size.height/2);
}
Shape create_rectangle(CSize size, const vec4 color)
{
int real_vertex_count = 4;
Params params = default_params();
params.const_params.datasize = sizeof(CPoint)*real_vertex_count;
params.const_params.triangle_mode = GL_TRIANGLE_STRIP;
CPoint *data = malloc(params.const_params.datasize);
gen_rectangle(data, size);
return (Shape) {{color[0], color[1], color[2], color[3]},
data,
create_vbo(params.const_params.datasize, data, GL_DYNAMIC_DRAW),
real_vertex_count,
params};
}
// ok
// Textured rectangle
static inline CPoint rectangle_texture_point(CPoint p, CSize size)
{
return CPointMake(1-(-p.x/size.width+.5), p.y/size.height+.5);
}
static inline void gen_textured_rectangle(CPoint* out, CSize size)
{
int offset=0;
out[offset++] = CPointMake(-size.width/2, -size.height/2);
out[offset++] = rectangle_texture_point(CPointMake(-size.width/2, -size.height/2), size);
out[offset++] = CPointMake(size.width/2, -size.height/2);
out[offset++] = rectangle_texture_point(CPointMake(size.width/2, -size.height/2), size);
out[offset++] = CPointMake(-size.width/2, size.height/2);
out[offset++] = rectangle_texture_point(CPointMake(-size.width/2, size.height/2), size);
out[offset++] = CPointMake(size.width/2, size.height/2);
out[offset++] = rectangle_texture_point(CPointMake(size.width/2, size.height/2), size);
}
TexturedShape create_textured_rectangle(CSize size, GLuint texture)
{
int real_vertex_count = 4;
Params params = default_params();
params.const_params.datasize = sizeof(CPoint) * real_vertex_count * 2;
params.const_params.triangle_mode = GL_TRIANGLE_STRIP;
CPoint *data = malloc(params.const_params.datasize);
gen_textured_rectangle(data, size);
return (TexturedShape) {texture,
data,
create_vbo(params.const_params.datasize, data, GL_STATIC_DRAW),
real_vertex_count,
params};
}
void change_textured_rectangle(TexturedShape* shape, CSize size)
{
//DEBUG_LOG_WRITE_D("fps","change_textured_rectangle");
gen_textured_rectangle((*shape).data, size);
glBindBuffer(GL_ARRAY_BUFFER, shape->buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, shape->params.const_params.datasize, shape->data); // proved
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// ok
// Ribbon
static inline void gen_ribbon(CPoint* out, float length)
{
int offset=0;
out[offset++] = CPointMake(-MAXf(length-5.5, 0), -5.5);
out[offset++] = CPointMake(0, -5.5);
out[offset++] = CPointMake(-MAXf(length, 0), 5.5);
out[offset++] = CPointMake(0, 5.5);
}
Shape create_ribbon(float length, const vec4 color)
{
int real_vertex_count = 4;
Params params=default_params();
params.const_params.datasize = sizeof(CPoint)*real_vertex_count;
params.const_params.triangle_mode = GL_TRIANGLE_STRIP;
params.var_params.side_length=length;
CPoint *data = malloc(params.const_params.datasize);
gen_ribbon(data, length);
return (Shape) {{color[0], color[1], color[2], color[3]},
data,
create_vbo(params.const_params.datasize, data, GL_DYNAMIC_DRAW),
real_vertex_count,
params};
}
void change_ribbon(Shape* shape, float length)
{
if ((*shape).params.var_params.side_length != length)
{
//DEBUG_LOG_WRITE_D("fps","change_segmented_square");
(*shape).params.var_params.side_length = length;
gen_ribbon((*shape).data, length);
glBindBuffer(GL_ARRAY_BUFFER, shape->buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, shape->params.const_params.datasize, shape->data); // proved
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
// ok
// Segmented circle
static inline int size_of_segmented_circle_in_vertices(int num_points) {
return 1 + (num_points + 1);
}
static inline void gen_segmented_circle(CPoint* out, float radius, float start_angle, float angle, int vertex_count)
{
int offset=0;
out[offset++] = CPointMake(0, 0);
int i;
for (i = 0; i <= vertex_count; i++) {
out[offset++] = CPointMake(radius*cos(start_angle+(i/(float)vertex_count)*angle), radius*sin(start_angle+(i/(float)vertex_count)*angle));
//int o=offset-1;
}
}
Shape create_segmented_circle(float radius, int vertex_count, float start_angle, float angle, const vec4 color)
{
int real_vertex_count = size_of_segmented_circle_in_vertices(vertex_count);
Params params=default_params();
params.const_params.datasize = sizeof(CPoint)*real_vertex_count;
params.const_params.triangle_mode=GL_TRIANGLE_FAN;
params.const_params.round_count=vertex_count;
CPoint *data = malloc(params.const_params.datasize);
gen_segmented_circle(data, radius, start_angle, angle, vertex_count);
return (Shape) {{color[0], color[1], color[2], color[3]},
data,
create_vbo(params.const_params.datasize, data, GL_DYNAMIC_DRAW),
real_vertex_count,
params};
}
void change_segmented_circle(Shape* shape, float radius, float start_angle, float angle)
{
if ((*shape).params.var_params.radius != radius ||
(*shape).params.var_params.start_angle != start_angle ||
(*shape).params.var_params.angle != angle )
{
//DEBUG_LOG_WRITE_D("fps","change_segmented_square");
(*shape).params.var_params.radius = radius;
(*shape).params.var_params.start_angle = start_angle;
(*shape).params.var_params.angle = angle;
gen_segmented_circle((*shape).data, radius, start_angle, angle, (*shape).params.const_params.round_count);
glBindBuffer(GL_ARRAY_BUFFER, shape->buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, shape->params.const_params.datasize, shape->data); // proved
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
// ok
// Circle
static inline int size_of_circle_in_vertices(int num_points) {
return 1 + (num_points + 1);
}
static inline void gen_circle(CPoint* out, float radius, int vertex_count)
{
int offset=0;
out[offset++] = CPointMake(0, 0);
int i;
for (i = 0; i <= vertex_count; i++) {
out[offset++] = CPointMake(radius*cos(2*M_PI*(i/(float)vertex_count)), radius*sin(2*M_PI*(i/(float)vertex_count)) );
}
}
Shape create_circle(float radius, int vertex_count, const vec4 color)
{
int real_vertex_count = size_of_segmented_circle_in_vertices(vertex_count);
Params params=default_params();
params.const_params.datasize = sizeof(CPoint)*real_vertex_count;
params.const_params.triangle_mode=GL_TRIANGLE_FAN;
params.const_params.round_count=vertex_count;
CPoint *data = malloc(params.const_params.datasize);
gen_circle(data, radius, vertex_count);
return (Shape) {{color[0], color[1], color[2], color[3]},
data,
create_vbo(params.const_params.datasize, data, GL_STATIC_DRAW),
real_vertex_count,
params};
}
void change_circle(Shape* shape, float radius)
{
if ((*shape).params.var_params.radius != radius)
{
//DEBUG_LOG_WRITE_D("fps","change_segmented_square");
(*shape).params.var_params.radius = radius;
gen_circle((*shape).data, radius, (*shape).params.const_params.round_count);
glBindBuffer(GL_ARRAY_BUFFER, shape->buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, shape->params.const_params.datasize, shape->data); // proved
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
// ok
// Infinity
int size_of_infinity_in_vertices(int segment_count)
{
return (segment_count+1)*2;
}
static inline void gen_infinity(CPoint* out, float width, float angle, int segment_count)
{
CPoint path[13];
path[0]=CPointMake(53,23);
path[1]=CPointMake(49,31);
path[2]=CPointMake(39,47);
path[3]=CPointMake(22,47);
path[4]=CPointMake(6,47);
path[5]=CPointMake(0,31);
path[6]=CPointMake(0,23);
path[7]=CPointMake(0,16);
path[8]=CPointMake(5,0);
path[9]=CPointMake(23,0);
path[10]=CPointMake(39,0);
path[11]=CPointMake(48,15);
path[12]=CPointMake(52,21);
int offset=0;
int seg;
for (seg=0; seg<=segment_count; seg++) {
float tt = ((float)seg/(float)segment_count)*angle;
int q=4;
float tstep=1./q;
int n = floor(tt/tstep);
if (seg >= segment_count) {
//n=n-1;//q-1;
}
//printf("n>%d\n", n);
CPoint a = path[0+3*n];;
CPoint p1 = path[1+3*n];
CPoint p2 = path[2+3*n];
CPoint b = path[3+3*n];
float t=(tt-tstep*n)*q;
float nt = 1.0f - t;
vec2 p = {a.x * nt * nt * nt + 3.0 * p1.x * nt * nt * t + 3.0 * p2.x * nt * t * t + b.x * t * t * t,
a.y * nt * nt * nt + 3.0 * p1.y * nt * nt * t + 3.0 * p2.y * nt * t * t + b.y * t * t * t};
vec2 tangent = {-3.0 * a.x * nt * nt + 3.0 * p1.x * (1.0 - 4.0 * t + 3.0 * t * t) + 3.0 * p2.x * (2.0 * t - 3.0 * t * t) + 3.0 * b.x * t * t,
-3.0 * a.y * nt * nt + 3.0 * p1.y * (1.0 - 4.0 * t + 3.0 * t * t) + 3.0 * p2.y * (2.0 * t - 3.0 * t * t) + 3.0 * b.y * t * t};
vec2 tan_norm = {-tangent[1], tangent[0]};
vec2 norm;
vec2_norm(norm, tan_norm);
vec2 v;
vec2 norm_scaled;
vec2_scale(norm_scaled, norm, +width/2.);
vec2_add(v, p, norm_scaled);
out[offset] = CPointMake(v[0], v[1]);
offset++;
vec2_scale(norm_scaled, norm, -width/2.);
vec2_add(v, p, norm_scaled);
out[offset] = CPointMake(v[0], v[1]);
offset++;
}
//printf("infinity_q>%d", offset);
}
Shape create_infinity(float width, float angle, int segment_count, const vec4 color)
{
int real_vertex_count = size_of_infinity_in_vertices(segment_count);
Params params=default_params();
params.const_params.datasize = sizeof(CPoint)*real_vertex_count;
params.const_params.triangle_mode=GL_TRIANGLE_STRIP;
params.const_params.round_count=segment_count;
params.var_params.width = width;
params.var_params.angle = angle;
CPoint *data = malloc(params.const_params.datasize);
gen_infinity(data, width, angle, segment_count);
return (Shape) {{color[0], color[1], color[2], color[3]},
data,
create_vbo(params.const_params.datasize, data, GL_DYNAMIC_DRAW),
real_vertex_count,
params};
}
void change_infinity(Shape* shape, float angle)
{
if ( (*shape).params.var_params.angle != angle )
{
(*shape).params.var_params.angle = angle;
gen_infinity(shape->data, (*shape).params.var_params.width, (*shape).params.var_params.angle, (*shape).params.const_params.round_count);
glBindBuffer(GL_ARRAY_BUFFER, shape->buffer);
glBufferData(GL_ARRAY_BUFFER, shape->params.const_params.datasize, shape->data, GL_DYNAMIC_DRAW); // proved
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
void draw_infinity(const Shape* shape, mat4x4 view_projection_matrix)
{
if (shape->params.alpha>0 && (fabs(shape->params.scale.x)>0 && fabs(shape->params.scale.y)>0 && fabs(shape->params.scale.z)>0))
{
mat4x4 model_view_projection_matrix;
mvp_matrix(model_view_projection_matrix, shape->params, view_projection_matrix);
glUseProgram(color_program.program);
glUniformMatrix4fv(color_program.u_mvp_matrix_location, 1, GL_FALSE, (GLfloat*)model_view_projection_matrix);
glUniform4fv(color_program.u_color_location, 1, shape->color);
glUniform1f(color_program.u_alpha_loaction, shape->params.alpha);
glVertexAttribPointer(color_program.a_position_location, 2, GL_FLOAT, GL_FALSE, sizeof(CPoint), &shape->data[0].x);
glEnableVertexAttribArray(color_program.a_position_location);
glDrawArrays(shape->params.const_params.triangle_mode, 0, shape->num_points);
}
}
// ok
// Rounded rectangle stroked
static inline int size_of_rounded_rectangle_stroked_in_vertices(int round_count) {
return 4*(2+round_count)*2+2;
}
static inline void gen_rounded_rectangle_stroked(CPoint* out, CSize size, float radius, float stroke_width, int round_count)
{
int offset=0;
float k = M_PI/2/(round_count+1);
float inner_radius = radius - stroke_width;
int i=0;
int n=0;
for (i=(round_count+2)*n; i<=round_count+1 + (round_count+1)*n; i++) {
out[offset++] = CPointMake(size.width/2-radius + cos(i*k)*radius, size.height/2-radius + sin(i*k)*radius);
out[offset++] = CPointMake(size.width/2-radius + cos(i*k)*inner_radius, size.height/2-radius + sin(i*k)*inner_radius);
}
n++;
for (i=(round_count+1)*n; i<=round_count+1 + (round_count+1)*n; i++) {
out[offset++] = CPointMake(-size.width/2+radius + cos(i*k)*radius, size.height/2-radius + sin(i*k)*radius);
out[offset++] = CPointMake(-size.width/2+radius + cos(i*k)*inner_radius, size.height/2-radius + sin(i*k)*inner_radius);
}
n++;
for (i=(round_count+1)*n; i<=round_count+1 + (round_count+1)*n; i++) {
out[offset++] = CPointMake(-size.width/2+radius + cos(i*k)*radius, -size.height/2+radius + sin(i*k)*radius);
out[offset++] = CPointMake(-size.width/2+radius + cos(i*k)*inner_radius, -size.height/2+radius + sin(i*k)*inner_radius);
}
n++;
for (i=(round_count+1)*n; i<=round_count+1 + (round_count+1)*n; i++) {
out[offset++] = CPointMake(size.width/2-radius + cos(i*k)*radius, -size.height/2+radius + sin(i*k)*radius);
out[offset++] = CPointMake(size.width/2-radius + cos(i*k)*inner_radius, -size.height/2+radius + sin(i*k)*inner_radius);
}
n++;
i=0;
out[offset++] = CPointMake(size.width/2-radius + cos(i*k)*radius, size.height/2-radius + sin(i*k)*radius);
out[offset++] = CPointMake(size.width/2-radius + cos(i*k)*inner_radius, size.height/2-radius + sin(i*k)*inner_radius);
}
Shape create_rounded_rectangle_stroked(CSize size, float radius, float stroke_width, int round_count, const vec4 color)
{
// round_count == 10 : polygons fall out
int real_vertex_count = size_of_rounded_rectangle_stroked_in_vertices(round_count);
Params params = default_params();
params.const_params.round_count=round_count;
params.const_params.datasize = sizeof(CPoint)*real_vertex_count*2;
params.var_params.size=size;
params.var_params.radius=radius;
params.var_params.width=stroke_width;
CPoint *data = malloc(params.const_params.datasize);
gen_rounded_rectangle_stroked(data, params.var_params.size, params.var_params.radius, params.var_params.width, params.const_params.round_count);
params.const_params.triangle_mode = GL_TRIANGLE_STRIP;
return (Shape) {{color[0], color[1], color[2], color[3]},
data,
create_vbo(params.const_params.datasize, data, GL_DYNAMIC_DRAW),
real_vertex_count,
params};
}
void change_rounded_rectangle_stroked(Shape* shape, CSize size, float radius, float stroke_width)
{
if ((*shape).params.var_params.size.width != size.width || (*shape).params.var_params.size.height != size.height || (*shape).params.var_params.radius != radius )
{
//DEBUG_LOG_WRITE_D("fps","change_rounded_rectangle");
(*shape).params.var_params.size.width = size.width;
(*shape).params.var_params.size.height = size.height;
(*shape).params.var_params.radius = radius;
gen_rounded_rectangle_stroked((*shape).data, (*shape).params.var_params.size, (*shape).params.var_params.radius, (*shape).params.var_params.width, (*shape).params.const_params.round_count);
glBindBuffer(GL_ARRAY_BUFFER, shape->buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, shape->params.const_params.datasize, shape->data); //
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}