src/2d.c

changeset 159
da7ebfcdd159
parent 158
f650994ec543
equal deleted inserted replaced
158:f650994ec543 159:da7ebfcdd159
35 #include <GL/glew.h> 35 #include <GL/glew.h>
36 36
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 border_color;
40 GLint size; 41 GLint size;
41 GLint thickness; 42 GLint thickness;
42 GLint radius; 43 GLint radius;
43 } AscRectangleShader; 44 } AscRectangleShader;
44 45
45 #define ASC_RECTANGLE_SHADER_FLAG_FILL 1 46 #define ASC_RECTANGLE_SHADER_FLAG_FILL 1
46 #define ASC_RECTANGLE_SHADER_FLAG_ROUND 2 47 #define ASC_RECTANGLE_SHADER_FLAG_ROUND 2
48 #define ASC_RECTANGLE_SHADER_FLAG_BORDER 4
47 49
48 static AscShaderProgram *asc_rectangle_shader_create(int flags) { 50 static AscShaderProgram *asc_rectangle_shader_create(int flags) {
49 AscShaderCodes codes; 51 AscShaderCodes codes;
52 // TODO: create a utility that rolls out those defines
50 const char * const defines[] = { 53 const char * const defines[] = {
51 "", 54 NULL,
52 "#define FILL", 55 "#define FILL",
53 "#define ROUNDED_CORNERS", 56 "#define BORDER\n#define ROUNDED_CORNERS",
54 "#define FILL\n#define ROUNDED_CORNERS", 57 "#define FILL\n#define ROUNDED_CORNERS",
58 "#define BORDER",
59 "#define BORDER\n#define FILL",
60 "#define BORDER\n#define ROUNDED_CORNERS",
61 "#define BORDER\n#define FILL\n#define ROUNDED_CORNERS",
55 }; 62 };
56 if (asc_shader_load_code_files((AscShaderCodeInfo){ 63 if (asc_shader_load_code_files((AscShaderCodeInfo){
57 .files.vtx = "sprite_vtx.glsl", 64 .files.vtx = "sprite_vtx.glsl",
58 .files.frag = "rectangle_frag.glsl", 65 .files.frag = "rectangle_frag.glsl",
59 .defines.frag = defines[flags], 66 .defines.frag = defines[flags],
64 AscRectangleShader *shader = asc_shader_create(codes, sizeof(*shader)); 71 AscRectangleShader *shader = asc_shader_create(codes, sizeof(*shader));
65 if (asc_has_error()) { 72 if (asc_has_error()) {
66 asc_shader_free_codes(codes); 73 asc_shader_free_codes(codes);
67 return NULL; 74 return NULL;
68 } 75 }
69 shader->color = glGetUniformLocation(shader->program.gl_id, "color");
70 shader->size = glGetUniformLocation(shader->program.gl_id, "size"); 76 shader->size = glGetUniformLocation(shader->program.gl_id, "size");
71 if (asc_test_flag(flags, ASC_RECTANGLE_SHADER_FLAG_FILL)) { 77 if (asc_test_flag(flags, ASC_RECTANGLE_SHADER_FLAG_FILL)) {
78 shader->color = glGetUniformLocation(shader->program.gl_id, "color");
79 } else {
80 shader->color = -1;
81 }
82 if (asc_test_flag(flags, ASC_RECTANGLE_SHADER_FLAG_BORDER)) {
83 shader->thickness = glGetUniformLocation(shader->program.gl_id, "thickness");
84 shader->border_color = glGetUniformLocation(shader->program.gl_id, "border_color");
85 } else {
72 shader->thickness = -1; 86 shader->thickness = -1;
73 } else { 87 shader->border_color = -1;
74 shader->thickness = glGetUniformLocation(shader->program.gl_id, "thickness");
75 } 88 }
76 if (asc_test_flag(flags, ASC_RECTANGLE_SHADER_FLAG_ROUND)) { 89 if (asc_test_flag(flags, ASC_RECTANGLE_SHADER_FLAG_ROUND)) {
77 shader->radius = glGetUniformLocation(shader->program.gl_id, "radius"); 90 shader->radius = glGetUniformLocation(shader->program.gl_id, "radius");
78 } else { 91 } else {
79 shader->radius = -1; 92 shader->radius = -1;
96 asc_mesh_plane_2d(&rectangle->mesh, .size = size, .uv_scale = size); 109 asc_mesh_plane_2d(&rectangle->mesh, .size = size, .uv_scale = size);
97 } 110 }
98 111
99 static void asc_rectangle_draw(const AscCamera *camera, const AscSceneNode *node) { 112 static void asc_rectangle_draw(const AscCamera *camera, const AscSceneNode *node) {
100 asc_ptr_cast(AscRectangle, rectangle, node); 113 asc_ptr_cast(AscRectangle, rectangle, node);
101 const bool filled = asc_test_flag(rectangle->flags, ASC_RECTANGLE_FILLED); 114 const bool filled = rectangle->filled;
102 const bool round = rectangle->radius > 0; 115 const bool round = rectangle->radius > 0;
116 const bool border = rectangle->thickness > 0;
103 117
104 // Compute shader flags 118 // Compute shader flags
105 int shader_flags = 0; 119 int shader_flags = 0;
106 if (filled) shader_flags |= ASC_RECTANGLE_SHADER_FLAG_FILL; 120 if (filled) shader_flags |= ASC_RECTANGLE_SHADER_FLAG_FILL;
121 if (border) shader_flags |= ASC_RECTANGLE_SHADER_FLAG_BORDER;
107 if (round) shader_flags |= ASC_RECTANGLE_SHADER_FLAG_ROUND; 122 if (round) shader_flags |= ASC_RECTANGLE_SHADER_FLAG_ROUND;
108 123
109 // Compute shader ID 124 // Compute shader ID
110 const int shader_ids[] = { 125 const int shader_ids[] = {
111 ASC_SHADER_RECTANGLE_DRAW, 126 -1, // unused
112 ASC_SHADER_RECTANGLE_FILL, 127 ASC_SHADER_RECTANGLE_FILL,
113 ASC_SHADER_RECTANGLE_DRAW_ROUND, 128 ASC_SHADER_RECTANGLE_DRAW_ROUND,
114 ASC_SHADER_RECTANGLE_FILL_ROUND, 129 ASC_SHADER_RECTANGLE_FILL_ROUND,
130 ASC_SHADER_RECTANGLE_DRAW,
131 ASC_SHADER_RECTANGLE_FILL_BORDER,
132 ASC_SHADER_RECTANGLE_DRAW_ROUND,
133 ASC_SHADER_RECTANGLE_FILL_BORDER_ROUND,
115 }; 134 };
116 135
117 // Look up and activate shader 136 // Look up and activate shader
118 const AscRectangleShader *shader = asc_shader_lookup_or_create( 137 const AscRectangleShader *shader = asc_shader_lookup_or_create(
119 shader_ids[shader_flags], asc_rectangle_shader_create, shader_flags); 138 shader_ids[shader_flags], asc_rectangle_shader_create, shader_flags);
122 // Upload uniforms 141 // Upload uniforms
123 // TODO: uploading model matrix could be a helper function 142 // TODO: uploading model matrix could be a helper function
124 glUniformMatrix4fv(shader->program.model, 1, 143 glUniformMatrix4fv(shader->program.model, 1,
125 GL_FALSE, node->world_transform); 144 GL_FALSE, node->world_transform);
126 145
127 glUniform4f(shader->color, 146 if (filled) {
128 rectangle->color.red, 147 glUniform4f(shader->color,
129 rectangle->color.green, 148 rectangle->color.red,
130 rectangle->color.blue, 149 rectangle->color.green,
131 rectangle->color.alpha 150 rectangle->color.blue,
132 ); 151 rectangle->color.alpha
152 );
153 }
133 glUniform2f(shader->size, rectangle->width, rectangle->height); 154 glUniform2f(shader->size, rectangle->width, rectangle->height);
134 155
135 if (!filled) { 156 if (border) {
136 glUniform1f(shader->thickness, rectangle->thickness); 157 glUniform1f(shader->thickness, rectangle->thickness);
158 glUniform4f(shader->border_color,
159 rectangle->border_color.red,
160 rectangle->border_color.green,
161 rectangle->border_color.blue,
162 rectangle->border_color.alpha
163 );
137 } 164 }
138 if (round) { 165 if (round) {
139 glUniform1f(shader->radius, rectangle->radius); 166 glUniform1f(shader->radius, rectangle->radius);
140 } 167 }
141 168
156 rectangle->node.position.y = (float) args.y; 183 rectangle->node.position.y = (float) args.y;
157 rectangle->width = (float) args.width; 184 rectangle->width = (float) args.width;
158 rectangle->height = (float) args.height; 185 rectangle->height = (float) args.height;
159 } 186 }
160 187
161 rectangle->thickness = ASC_NONZERO_OR(1.f, args.thickness);
162 rectangle->radius = (float)args.radius; 188 rectangle->radius = (float)args.radius;
163 rectangle->color = asc_col_itof(asc_context.ink); 189 rectangle->color = asc_col_itof(asc_context.ink);
164 190 rectangle->border_color = asc_col_itof(args.border_color);
165 if (args.filled) { 191 rectangle->filled = args.filled;
166 asc_set_flag(rectangle->flags, ASC_RECTANGLE_FILLED); 192 if (!args.filled && args.thickness == 0) {
193 // when we do not fill the rectangle, we need a border
194 rectangle->thickness = 1;
195 } else {
196 rectangle->thickness = args.thickness;
197 }
198 if (!args.filled && asc_col4_test_zero(args.border_color)) {
199 // convenience fallback:
200 // when we are drawing an outline but have no explicit border color,
201 // use the active ink
202 rectangle->border_color = rectangle->color;
167 } 203 }
168 204
169 AscSceneNode *node = &rectangle->node; 205 AscSceneNode *node = &rectangle->node;
170 node->position.z = ASC_SCENE_2D_DEPTH_OFFSET; 206 node->position.z = ASC_SCENE_2D_DEPTH_OFFSET;
171 node->scale = asc_vec3f_one; 207 node->scale = asc_vec3f_one;

mercurial