1/* libs/opengles/vertex.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include <stdio.h>
19#include <stdlib.h>
20#include "context.h"
21#include "fp.h"
22#include "vertex.h"
23#include "state.h"
24#include "matrix.h"
25
26namespace android {
27
28// ----------------------------------------------------------------------------
29
30void ogles_init_vertex(ogles_context_t* c)
31{
32    c->cull.enable = GL_FALSE;
33    c->cull.cullFace = GL_BACK;
34    c->cull.frontFace = GL_CCW;
35
36    c->current.color.r = 0x10000;
37    c->current.color.g = 0x10000;
38    c->current.color.b = 0x10000;
39    c->current.color.a = 0x10000;
40
41    c->currentNormal.z = 0x10000;
42}
43
44void ogles_uninit_vertex(ogles_context_t* c)
45{
46}
47
48// ----------------------------------------------------------------------------
49// vertex processing
50// ----------------------------------------------------------------------------
51
52// Divides a vertex clip coordinates by W
53static inline
54void perspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
55{
56    // [x,y,z]window = vpt * ([x,y,z]clip / clip.w)
57    // [w]window = 1/w
58
59    // With a regular projection generated by glFrustum(),
60    // we have w=-z, therefore, w is in [zNear, zFar].
61    // Also, zNear and zFar are stricly positive,
62    // and 1/w (window.w) is in [1/zFar, 1/zNear], usually this
63    // means ]0, +inf[ -- however, it is always recommended
64    // to use as large values as possible for zNear.
65    // All in all, w is usually smaller than 1.0 (assuming
66    // zNear is at least 1.0); and even if zNear is smaller than 1.0
67    // values of w won't be too big.
68
69    const int32_t rw = gglRecip28(v->clip.w);
70    const GLfixed* const m = c->transforms.vpt.transform.matrix.m;
71    v->window.w = rw;
72    v->window.x = gglMulAddx(gglMulx(v->clip.x, rw, 16), m[ 0], m[12], 28);
73    v->window.y = gglMulAddx(gglMulx(v->clip.y, rw, 16), m[ 5], m[13], 28);
74    v->window.x = TRI_FROM_FIXED(v->window.x);
75    v->window.y = TRI_FROM_FIXED(v->window.y);
76    if (enables & GGL_ENABLE_DEPTH_TEST) {
77        v->window.z = gglMulAddx(gglMulx(v->clip.z, rw, 16), m[10], m[14], 28);
78    }
79}
80
81// frustum clipping and W-divide
82static inline
83void clipFrustumPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
84{
85    // ndc = clip / W
86    // window = ncd * viewport
87
88    // clip to the view-volume
89    uint32_t clip = v->flags & vertex_t::CLIP_ALL;
90    const GLfixed w = v->clip.w;
91    if (v->clip.x < -w)   clip |= vertex_t::CLIP_L;
92    if (v->clip.x >  w)   clip |= vertex_t::CLIP_R;
93    if (v->clip.y < -w)   clip |= vertex_t::CLIP_B;
94    if (v->clip.y >  w)   clip |= vertex_t::CLIP_T;
95    if (v->clip.z < -w)   clip |= vertex_t::CLIP_N;
96    if (v->clip.z >  w)   clip |= vertex_t::CLIP_F;
97
98    v->flags |= clip;
99    c->arrays.cull &= clip;
100
101    if (ggl_likely(!clip)) {
102        // if the vertex is clipped, we don't do the perspective
103        // divide, since we don't need its window coordinates.
104        perspective(c, v, enables);
105    }
106}
107
108// frustum clipping, user clipping and W-divide
109static inline
110void clipAllPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
111{
112    // compute eye coordinates
113    c->arrays.mv_transform(
114            &c->transforms.modelview.transform, &v->eye, &v->obj);
115    v->flags |= vertex_t::EYE;
116
117    // clip this vertex against each user clip plane
118    uint32_t clip = 0;
119    int planes = c->clipPlanes.enable;
120    while (planes) {
121        const int i = 31 - gglClz(planes);
122        planes &= ~(1<<i);
123        // XXX: we should have a special dot() for 2,3,4 coords vertices
124        GLfixed d = dot4(c->clipPlanes.plane[i].equation.v, v->eye.v);
125        if (d < 0) {
126            clip |= 0x100<<i;
127        }
128    }
129    v->flags |= clip;
130
131    clipFrustumPerspective(c, v, enables);
132}
133
134// ----------------------------------------------------------------------------
135
136void ogles_vertex_project(ogles_context_t* c, vertex_t* v) {
137    perspective(c, v, c->rasterizer.state.enables);
138}
139
140void ogles_vertex_perspective2D(ogles_context_t* c, vertex_t* v)
141{
142    // here we assume w=1.0 and the viewport transformation
143    // has been applied already.
144    c->arrays.cull = 0;
145    v->window.x = TRI_FROM_FIXED(v->clip.x);
146    v->window.y = TRI_FROM_FIXED(v->clip.y);
147    v->window.z = v->clip.z;
148    v->window.w = v->clip.w << 12;
149}
150
151void ogles_vertex_perspective3DZ(ogles_context_t* c, vertex_t* v) {
152    clipFrustumPerspective(c, v, GGL_ENABLE_DEPTH_TEST);
153}
154void ogles_vertex_perspective3D(ogles_context_t* c, vertex_t* v) {
155    clipFrustumPerspective(c, v, 0);
156}
157void ogles_vertex_clipAllPerspective3DZ(ogles_context_t* c, vertex_t* v) {
158    clipAllPerspective(c, v, GGL_ENABLE_DEPTH_TEST);
159}
160void ogles_vertex_clipAllPerspective3D(ogles_context_t* c, vertex_t* v) {
161    clipAllPerspective(c, v, 0);
162}
163
164static void clipPlanex(GLenum plane, const GLfixed* equ, ogles_context_t* c)
165{
166    const int p = plane - GL_CLIP_PLANE0;
167    if (ggl_unlikely(uint32_t(p) > (GL_CLIP_PLANE5 - GL_CLIP_PLANE0))) {
168        ogles_error(c, GL_INVALID_ENUM);
169        return;
170    }
171
172    vec4_t& equation = c->clipPlanes.plane[p].equation;
173    memcpy(equation.v, equ, sizeof(vec4_t));
174
175    ogles_validate_transform(c, transform_state_t::MVIT);
176    transform_t& mvit = c->transforms.mvit4;
177    mvit.point4(&mvit, &equation, &equation);
178}
179
180// ----------------------------------------------------------------------------
181}; // namespace android
182// ----------------------------------------------------------------------------
183
184using namespace android;
185
186
187void glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
188{
189    ogles_context_t* c = ogles_context_t::get();
190    c->current.color.r       = gglFloatToFixed(r);
191    c->currentColorClamped.r = gglClampx(c->current.color.r);
192    c->current.color.g       = gglFloatToFixed(g);
193    c->currentColorClamped.g = gglClampx(c->current.color.g);
194    c->current.color.b       = gglFloatToFixed(b);
195    c->currentColorClamped.b = gglClampx(c->current.color.b);
196    c->current.color.a       = gglFloatToFixed(a);
197    c->currentColorClamped.a = gglClampx(c->current.color.a);
198}
199
200void glColor4x(GLfixed r, GLfixed g, GLfixed b, GLfixed a)
201{
202    ogles_context_t* c = ogles_context_t::get();
203    c->current.color.r = r;
204    c->current.color.g = g;
205    c->current.color.b = b;
206    c->current.color.a = a;
207    c->currentColorClamped.r = gglClampx(r);
208    c->currentColorClamped.g = gglClampx(g);
209    c->currentColorClamped.b = gglClampx(b);
210    c->currentColorClamped.a = gglClampx(a);
211}
212
213void glNormal3f(GLfloat x, GLfloat y, GLfloat z)
214{
215    ogles_context_t* c = ogles_context_t::get();
216    c->currentNormal.x = gglFloatToFixed(x);
217    c->currentNormal.y = gglFloatToFixed(y);
218    c->currentNormal.z = gglFloatToFixed(z);
219}
220
221void glNormal3x(GLfixed x, GLfixed y, GLfixed z)
222{
223    ogles_context_t* c = ogles_context_t::get();
224    c->currentNormal.x = x;
225    c->currentNormal.y = y;
226    c->currentNormal.z = z;
227}
228
229// ----------------------------------------------------------------------------
230
231void glClipPlanef(GLenum plane, const GLfloat* equ)
232{
233    const GLfixed equx[4] = {
234            gglFloatToFixed(equ[0]),
235            gglFloatToFixed(equ[1]),
236            gglFloatToFixed(equ[2]),
237            gglFloatToFixed(equ[3])
238    };
239    ogles_context_t* c = ogles_context_t::get();
240    clipPlanex(plane, equx, c);
241}
242
243void glClipPlanex(GLenum plane, const GLfixed* equ)
244{
245    ogles_context_t* c = ogles_context_t::get();
246    clipPlanex(plane, equ, c);
247}
248