37 typedef struct asc_rectangle_shader_s { |
37 typedef struct asc_rectangle_shader_s { |
38 AscShaderProgram program; |
38 AscShaderProgram program; |
39 GLint color; |
39 GLint color; |
40 GLint size; |
40 GLint size; |
41 GLint thickness; |
41 GLint thickness; |
|
42 GLint radius; |
42 } AscRectangleShader; |
43 } AscRectangleShader; |
43 |
44 |
44 static void *asc_rectangle_shader_create(bool fill) { |
45 #define ASC_RECTANGLE_SHADER_FLAG_FILL 1 |
|
46 #define ASC_RECTANGLE_SHADER_FLAG_ROUND 2 |
|
47 |
|
48 static AscShaderProgram *asc_rectangle_shader_create(int flags) { |
45 AscShaderCodes codes; |
49 AscShaderCodes codes; |
|
50 const char * const defines[] = { |
|
51 "", |
|
52 "#define FILL", |
|
53 "#define ROUNDED_CORNERS", |
|
54 "#define FILL\n#define ROUNDED_CORNERS", |
|
55 }; |
46 if (asc_shader_load_code_files((AscShaderCodeInfo){ |
56 if (asc_shader_load_code_files((AscShaderCodeInfo){ |
47 .files.vtx = "sprite_vtx.glsl", |
57 .files.vtx = "sprite_vtx.glsl", |
48 .files.frag = "rectangle_frag.glsl", |
58 .files.frag = "rectangle_frag.glsl", |
49 .defines.frag = fill ? "#define FILL" : NULL, |
59 .defines.frag = defines[flags], |
50 }, &codes)) { |
60 }, &codes)) { |
51 asc_error("Loading sprite shader failed."); |
61 asc_error("Loading sprite shader failed."); |
52 return NULL; |
62 return NULL; |
53 } |
63 } |
54 AscRectangleShader *shader = asc_shader_create(codes, sizeof(*shader)); |
64 AscRectangleShader *shader = asc_shader_create(codes, sizeof(*shader)); |
56 asc_shader_free_codes(codes); |
66 asc_shader_free_codes(codes); |
57 return NULL; |
67 return NULL; |
58 } |
68 } |
59 shader->color = glGetUniformLocation(shader->program.gl_id, "color"); |
69 shader->color = glGetUniformLocation(shader->program.gl_id, "color"); |
60 shader->size = glGetUniformLocation(shader->program.gl_id, "size"); |
70 shader->size = glGetUniformLocation(shader->program.gl_id, "size"); |
61 if (fill) { |
71 if (asc_test_flag(flags, ASC_RECTANGLE_SHADER_FLAG_FILL)) { |
62 shader->thickness = -1; |
72 shader->thickness = -1; |
63 } else { |
73 } else { |
64 shader->thickness = glGetUniformLocation(shader->program.gl_id, "thickness"); |
74 shader->thickness = glGetUniformLocation(shader->program.gl_id, "thickness"); |
|
75 } |
|
76 if (asc_test_flag(flags, ASC_RECTANGLE_SHADER_FLAG_ROUND)) { |
|
77 shader->radius = glGetUniformLocation(shader->program.gl_id, "radius"); |
|
78 } else { |
|
79 shader->radius = -1; |
65 } |
80 } |
66 asc_shader_free_codes(codes); |
81 asc_shader_free_codes(codes); |
67 |
82 |
68 asc_error_catch_all_gl(); |
83 asc_error_catch_all_gl(); |
69 |
84 |
70 return shader; |
85 return (AscShaderProgram*) shader; |
71 } |
|
72 |
|
73 static AscShaderProgram *asc_rectangle_shader_fill_create() { |
|
74 return asc_rectangle_shader_create(true); |
|
75 } |
|
76 |
|
77 static AscShaderProgram *asc_rectangle_shader_draw_create() { |
|
78 return asc_rectangle_shader_create(false); |
|
79 } |
|
80 |
|
81 static const AscRectangleShader *asc_rectangle_shader_draw(void) { |
|
82 return asc_shader_lookup_or_create(ASC_SHADER_RECTANGLE_DRAW, asc_rectangle_shader_draw_create); |
|
83 } |
|
84 |
|
85 static const AscRectangleShader *asc_rectangle_shader_fill(void) { |
|
86 return asc_shader_lookup_or_create(ASC_SHADER_RECTANGLE_FILL, asc_rectangle_shader_fill_create); |
|
87 } |
86 } |
88 |
87 |
89 static void asc_rectangle_destroy(AscSceneNode *node) { |
88 static void asc_rectangle_destroy(AscSceneNode *node) { |
90 asc_ptr_cast(AscRectangle, rectangle, node); |
89 asc_ptr_cast(AscRectangle, rectangle, node); |
91 asc_mesh_destroy(&rectangle->mesh); |
90 asc_mesh_destroy(&rectangle->mesh); |
97 asc_mesh_plane_2d(&rectangle->mesh, .size = size, .uv_scale = size); |
96 asc_mesh_plane_2d(&rectangle->mesh, .size = size, .uv_scale = size); |
98 } |
97 } |
99 |
98 |
100 static void asc_rectangle_draw(const AscCamera *camera, const AscSceneNode *node) { |
99 static void asc_rectangle_draw(const AscCamera *camera, const AscSceneNode *node) { |
101 asc_ptr_cast(AscRectangle, rectangle, node); |
100 asc_ptr_cast(AscRectangle, rectangle, node); |
102 bool filled = asc_test_flag(rectangle->flags, ASC_RECTANGLE_FILLED); |
101 const bool filled = asc_test_flag(rectangle->flags, ASC_RECTANGLE_FILLED); |
|
102 const bool round = rectangle->radius > 0; |
103 |
103 |
104 // Activate shader |
104 // Compute shader flags |
105 // TODO: scene should know which shader we are going to activate s.t. it can pre-sort nodes |
105 int shader_flags = 0; |
106 const AscRectangleShader *shader = filled |
106 if (filled) shader_flags |= ASC_RECTANGLE_SHADER_FLAG_FILL; |
107 ? asc_rectangle_shader_fill() |
107 if (round) shader_flags |= ASC_RECTANGLE_SHADER_FLAG_ROUND; |
108 : asc_rectangle_shader_draw(); |
108 |
|
109 // Compute shader ID |
|
110 const int shader_ids[] = { |
|
111 ASC_SHADER_RECTANGLE_DRAW, |
|
112 ASC_SHADER_RECTANGLE_FILL, |
|
113 ASC_SHADER_RECTANGLE_DRAW_ROUND, |
|
114 ASC_SHADER_RECTANGLE_FILL_ROUND, |
|
115 }; |
|
116 |
|
117 // Look up and activate shader |
|
118 const AscRectangleShader *shader = asc_shader_lookup_or_create( |
|
119 shader_ids[shader_flags], asc_rectangle_shader_create, shader_flags); |
109 asc_shader_use(&shader->program, camera); |
120 asc_shader_use(&shader->program, camera); |
110 |
121 |
111 // Upload uniforms |
122 // Upload uniforms |
112 // TODO: uploading model matrix could be a helper function |
123 // TODO: uploading model matrix could be a helper function |
113 glUniformMatrix4fv(shader->program.model, 1, |
124 glUniformMatrix4fv(shader->program.model, 1, |
117 rectangle->color.red, |
128 rectangle->color.red, |
118 rectangle->color.green, |
129 rectangle->color.green, |
119 rectangle->color.blue, |
130 rectangle->color.blue, |
120 rectangle->color.alpha |
131 rectangle->color.alpha |
121 ); |
132 ); |
122 glUniform2f(shader->size, (float) rectangle->width, (float) rectangle->height); |
133 glUniform2f(shader->size, rectangle->width, rectangle->height); |
123 |
134 |
124 if (!filled) { |
135 if (!filled) { |
125 // TODO: implement thickness |
136 glUniform1f(shader->thickness, rectangle->thickness); |
126 glUniform1f(shader->thickness, 1); |
137 } |
|
138 if (round) { |
|
139 glUniform1f(shader->radius, rectangle->radius); |
127 } |
140 } |
128 |
141 |
129 // Draw mesh |
142 // Draw mesh |
130 asc_mesh_draw_triangle_strip(&rectangle->mesh); |
143 asc_mesh_draw_triangle_strip(&rectangle->mesh); |
131 } |
144 } |
134 AscRectangle *rectangle = cxZallocDefault(sizeof(AscRectangle)); |
147 AscRectangle *rectangle = cxZallocDefault(sizeof(AscRectangle)); |
135 |
148 |
136 if (args.bounds.size.width + args.bounds.size.height > 0) { |
149 if (args.bounds.size.width + args.bounds.size.height > 0) { |
137 rectangle->node.position.x = (float) args.bounds.pos.x; |
150 rectangle->node.position.x = (float) args.bounds.pos.x; |
138 rectangle->node.position.y = (float) args.bounds.pos.y; |
151 rectangle->node.position.y = (float) args.bounds.pos.y; |
139 rectangle->width = args.bounds.size.width; |
152 rectangle->width = (float) args.bounds.size.width; |
140 rectangle->height = args.bounds.size.height; |
153 rectangle->height = (float) args.bounds.size.height; |
141 } else { |
154 } else { |
142 rectangle->node.position.x = (float) args.x; |
155 rectangle->node.position.x = (float) args.x; |
143 rectangle->node.position.y = (float) args.y; |
156 rectangle->node.position.y = (float) args.y; |
144 rectangle->width = args.width; |
157 rectangle->width = (float) args.width; |
145 rectangle->height = args.height; |
158 rectangle->height = (float) args.height; |
146 } |
159 } |
147 |
160 |
|
161 rectangle->thickness = ASC_NONZERO_OR(1.f, args.thickness); |
|
162 rectangle->radius = (float)args.radius; |
148 rectangle->color = asc_col_itof(asc_context.ink); |
163 rectangle->color = asc_col_itof(asc_context.ink); |
149 |
164 |
150 if (args.filled) { |
165 if (args.filled) { |
151 asc_set_flag(rectangle->flags, ASC_RECTANGLE_FILLED); |
166 asc_set_flag(rectangle->flags, ASC_RECTANGLE_FILLED); |
152 } |
167 } |