79508e6168eacc4e4975f3e4236fe0fcd9be0199
[simavr] / examples / shared / libc3 / src / c3context.c
1 /*
2         c3context.c
3
4         Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
5
6         This file is part of libc3.
7
8         libc3 is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         libc3 is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with libc3.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <math.h>
23 #include "c3context.h"
24 #include "c3object.h"
25 #include "c3driver_context.h"
26
27 c3context_p
28 c3context_new(
29                 int w,
30                 int h)
31 {
32         c3context_p res = malloc(sizeof(*res));
33         return c3context_init(res, w, h);
34 }
35
36 c3context_p
37 c3context_init(
38                 c3context_p c,
39                 int w,
40                 int h)
41 {
42         memset(c, 0, sizeof(*c));
43
44         c3context_view_t v = {
45                         .type = C3_CONTEXT_VIEW_EYE,
46                         .size = c3vec2f(w, h),
47                         .cam = c3cam_new(),
48                         .dirty = 1,
49         };
50         c3context_view_array_add(&c->views, v);
51         c->root = c3object_new(NULL);
52         c->root->context = c;
53
54         return c;
55 }
56
57 void
58 c3context_dispose(
59                 c3context_p c)
60 {
61         c3object_dispose(c->root);
62         for (int i = 0; i < c->views.count; i++)
63                 c3geometry_array_free(&c->views.e[i].projected);
64         free(c);
65 }
66
67 static c3context_view_p qsort_view;
68
69 /*
70  * Computes the distance from the 'eye' of the camera, sort by this value
71  */
72 static int
73 _c3_z_sorter(
74                 const void *_p1,
75                 const void *_p2)
76 {
77         c3geometry_p g1 = *(c3geometry_p*)_p1;
78         c3geometry_p g2 = *(c3geometry_p*)_p2;
79         // get center of bboxes
80         c3vec3 c1 = c3vec3_add(g1->bbox.min, c3vec3_divf(c3vec3_sub(g1->bbox.max, g1->bbox.min), 2));
81         c3vec3 c2 = c3vec3_add(g2->bbox.min, c3vec3_divf(c3vec3_sub(g2->bbox.max, g2->bbox.min), 2));
82
83         c3cam_p cam = &qsort_view->cam;
84         c3f d1 = c3vec3_length2(c3vec3_sub(c1, cam->eye));
85         c3f d2 = c3vec3_length2(c3vec3_sub(c2, cam->eye));
86
87         if (d1 > qsort_view->z.max) qsort_view->z.max = d1;
88         if (d1 < qsort_view->z.min) qsort_view->z.min = d1;
89         if (d2 > qsort_view->z.max) qsort_view->z.max = d2;
90         if (d2 < qsort_view->z.min) qsort_view->z.min = d2;
91         /*
92          * make sure transparent items are drawn after everyone else
93          */
94         if (g1->mat.color.n[3] < 1)
95                 d1 -= 100000.0;
96         if (g2->mat.color.n[3] < 1)
97                 d2 -= 100000.0;
98
99         return d1 < d2 ? 1 : d1 > d2 ? -1 : 0;
100 }
101
102 void
103 c3context_project(
104                 c3context_p c)
105 {
106         if (!c->root)
107                 return;
108
109         /*
110          * if the root object is dirty, all the views are also
111          * dirty since the geometry has changed
112          */
113         if (c->root->dirty) {
114                 for (int ci = 0; ci < c->views.count; ci++)
115                         c->views.e[ci].dirty = 1;
116                 c3mat4 m = identity3D();
117                 c3object_project(c->root, &m);
118         }
119
120         /*
121          * if the current view is dirty, gather all the geometry
122          * and Z sort it in a basic way
123          */
124         c3context_view_p v = qsort_view = c3context_view_get(c);
125         if (v->dirty) {
126             c3cam_update_matrix(&v->cam);
127
128                 c3geometry_array_p  array = &c3context_view_get(c)->projected;
129                 c3geometry_array_clear(array);
130                 c3object_get_geometry(c->root, array);
131
132                 v->z.min = 1000000000;
133                 v->z.max = -1000000000;
134
135                 qsort(v->projected.e,
136                                 v->projected.count, sizeof(v->projected.e[0]),
137                         _c3_z_sorter);
138                 v->z.min = sqrt(v->z.min);
139                 v->z.max = sqrt(v->z.max);
140
141                 v->dirty = 0;
142         }
143 }
144
145 void
146 c3context_draw(
147                 c3context_p c)
148 {
149         c3context_project(c);
150
151         c3geometry_array_p  array = &c3context_view_get(c)->projected;
152         for (int gi = 0; gi < array->count; gi++) {
153                 c3geometry_p g = array->e[gi];
154                 c3geometry_draw(g);
155         }
156 }