12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112 |
- /* libs/opengles/primitives.cpp
- **
- ** Copyright 2006, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include "context.h"
- #include "primitives.h"
- #include "light.h"
- #include "matrix.h"
- #include "vertex.h"
- #include "fp.h"
- #include "TextureObjectManager.h"
- extern "C" void iterators0032(const void* that,
- int32_t* it, int32_t c0, int32_t c1, int32_t c2);
- namespace android {
- // ----------------------------------------------------------------------------
- static void primitive_point(ogles_context_t* c, vertex_t* v);
- static void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1);
- static void primitive_clip_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
- static void primitive_nop_point(ogles_context_t* c, vertex_t* v);
- static void primitive_nop_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1);
- static void primitive_nop_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
- static inline bool cull_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
- static void lerp_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
- static void lerp_texcoords(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
- static void lerp_texcoords_w(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
- static void triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
- static void clip_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
- static unsigned int clip_line(ogles_context_t* c,
- vertex_t* s, vertex_t* p);
- // ----------------------------------------------------------------------------
- #if 0
- #pragma mark -
- #endif
- static void lightTriangleDarkSmooth(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- if (!(v0->flags & vertex_t::LIT)) {
- v0->flags |= vertex_t::LIT;
- const GLvoid* cp = c->arrays.color.element(
- v0->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v0->color.v, cp);
- }
- if (!(v1->flags & vertex_t::LIT)) {
- v1->flags |= vertex_t::LIT;
- const GLvoid* cp = c->arrays.color.element(
- v1->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v1->color.v, cp);
- }
- if(!(v2->flags & vertex_t::LIT)) {
- v2->flags |= vertex_t::LIT;
- const GLvoid* cp = c->arrays.color.element(
- v2->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v2->color.v, cp);
- }
- }
- static void lightTriangleDarkFlat(ogles_context_t* c,
- vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* v2)
- {
- if (!(v2->flags & vertex_t::LIT)) {
- v2->flags |= vertex_t::LIT;
- const GLvoid* cp = c->arrays.color.element(
- v2->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v2->color.v, cp);
- }
- // configure the rasterizer here, before we clip
- c->rasterizer.procs.color4xv(c, v2->color.v);
- }
- static void lightTriangleSmooth(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- if (!(v0->flags & vertex_t::LIT))
- c->lighting.lightVertex(c, v0);
- if (!(v1->flags & vertex_t::LIT))
- c->lighting.lightVertex(c, v1);
- if(!(v2->flags & vertex_t::LIT))
- c->lighting.lightVertex(c, v2);
- }
- static void lightTriangleFlat(ogles_context_t* c,
- vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* v2)
- {
- if (!(v2->flags & vertex_t::LIT))
- c->lighting.lightVertex(c, v2);
- // configure the rasterizer here, before we clip
- c->rasterizer.procs.color4xv(c, v2->color.v);
- }
- // The fog versions...
- static inline
- void lightVertexDarkSmoothFog(ogles_context_t* c, vertex_t* v)
- {
- if (!(v->flags & vertex_t::LIT)) {
- v->flags |= vertex_t::LIT;
- v->fog = c->fog.fog(c, v->eye.z);
- const GLvoid* cp = c->arrays.color.element(
- v->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v->color.v, cp);
- }
- }
- static inline
- void lightVertexDarkFlatFog(ogles_context_t* c, vertex_t* v)
- {
- if (!(v->flags & vertex_t::LIT)) {
- v->flags |= vertex_t::LIT;
- v->fog = c->fog.fog(c, v->eye.z);
- }
- }
- static inline
- void lightVertexSmoothFog(ogles_context_t* c, vertex_t* v)
- {
- if (!(v->flags & vertex_t::LIT)) {
- v->fog = c->fog.fog(c, v->eye.z);
- c->lighting.lightVertex(c, v);
- }
- }
- static void lightTriangleDarkSmoothFog(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- lightVertexDarkSmoothFog(c, v0);
- lightVertexDarkSmoothFog(c, v1);
- lightVertexDarkSmoothFog(c, v2);
- }
- static void lightTriangleDarkFlatFog(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- lightVertexDarkFlatFog(c, v0);
- lightVertexDarkFlatFog(c, v1);
- lightVertexDarkSmoothFog(c, v2);
- // configure the rasterizer here, before we clip
- c->rasterizer.procs.color4xv(c, v2->color.v);
- }
- static void lightTriangleSmoothFog(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- lightVertexSmoothFog(c, v0);
- lightVertexSmoothFog(c, v1);
- lightVertexSmoothFog(c, v2);
- }
- static void lightTriangleFlatFog(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- lightVertexDarkFlatFog(c, v0);
- lightVertexDarkFlatFog(c, v1);
- lightVertexSmoothFog(c, v2);
- // configure the rasterizer here, before we clip
- c->rasterizer.procs.color4xv(c, v2->color.v);
- }
- typedef void (*light_primitive_t)(ogles_context_t*,
- vertex_t*, vertex_t*, vertex_t*);
- // fog 0x4, light 0x2, smooth 0x1
- static const light_primitive_t lightPrimitive[8] = {
- lightTriangleDarkFlat, // no fog | dark | flat
- lightTriangleDarkSmooth, // no fog | dark | smooth
- lightTriangleFlat, // no fog | light | flat
- lightTriangleSmooth, // no fog | light | smooth
- lightTriangleDarkFlatFog, // fog | dark | flat
- lightTriangleDarkSmoothFog, // fog | dark | smooth
- lightTriangleFlatFog, // fog | light | flat
- lightTriangleSmoothFog // fog | light | smooth
- };
- void ogles_validate_primitives(ogles_context_t* c)
- {
- const uint32_t enables = c->rasterizer.state.enables;
- // set up the lighting/shading/smoothing/fogging function
- int index = enables & GGL_ENABLE_SMOOTH ? 0x1 : 0;
- index |= c->lighting.enable ? 0x2 : 0;
- index |= enables & GGL_ENABLE_FOG ? 0x4 : 0;
- c->lighting.lightTriangle = lightPrimitive[index];
-
- // set up the primitive renderers
- if (ggl_likely(c->arrays.vertex.enable)) {
- c->prims.renderPoint = primitive_point;
- c->prims.renderLine = primitive_line;
- c->prims.renderTriangle = primitive_clip_triangle;
- } else {
- c->prims.renderPoint = primitive_nop_point;
- c->prims.renderLine = primitive_nop_line;
- c->prims.renderTriangle = primitive_nop_triangle;
- }
- }
- // ----------------------------------------------------------------------------
- void compute_iterators_t::initTriangle(
- vertex_t const* v0, vertex_t const* v1, vertex_t const* v2)
- {
- m_dx01 = v1->window.x - v0->window.x;
- m_dy10 = v0->window.y - v1->window.y;
- m_dx20 = v0->window.x - v2->window.x;
- m_dy02 = v2->window.y - v0->window.y;
- m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20;
- }
- void compute_iterators_t::initLine(
- vertex_t const* v0, vertex_t const* v1)
- {
- m_dx01 = m_dy02 = v1->window.x - v0->window.x;
- m_dy10 = m_dx20 = v0->window.y - v1->window.y;
- m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20;
- }
- void compute_iterators_t::initLerp(vertex_t const* v0, uint32_t enables)
- {
- m_x0 = v0->window.x;
- m_y0 = v0->window.y;
- const GGLcoord area = (m_area + TRI_HALF) >> TRI_FRACTION_BITS;
- const GGLcoord minArea = 2; // cannot be inverted
- // triangles with an area smaller than 1.0 are not smooth-shaded
- int q=0, s=0, d=0;
- if (abs(area) >= minArea) {
- // Here we do some voodoo magic, to compute a suitable scale
- // factor for deltas/area:
- // First compute the 1/area with full 32-bits precision,
- // gglRecipQNormalized returns a number [-0.5, 0.5[ and an exponent.
- d = gglRecipQNormalized(area, &q);
- // Then compute the minimum left-shift to not overflow the muls
- // below.
- s = 32 - gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20));
- // We'll keep 16-bits of precision for deltas/area. So we need
- // to shift everything left an extra 15 bits.
- s += 15;
-
- // make sure all final shifts are not > 32, because gglMulx
- // can't handle it.
- if (s < q) s = q;
- if (s > 32) {
- d >>= 32-s;
- s = 32;
- }
- }
- m_dx01 = gglMulx(m_dx01, d, s);
- m_dy10 = gglMulx(m_dy10, d, s);
- m_dx20 = gglMulx(m_dx20, d, s);
- m_dy02 = gglMulx(m_dy02, d, s);
- m_area_scale = 32 + q - s;
- m_scale = 0;
- if (enables & GGL_ENABLE_TMUS) {
- const int A = gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20));
- const int B = gglClz(abs(m_x0)|abs(m_y0));
- m_scale = max(0, 32 - (A + 16)) +
- max(0, 32 - (B + TRI_FRACTION_BITS)) + 1;
- }
- }
- int compute_iterators_t::iteratorsScale(GGLfixed* it,
- int32_t c0, int32_t c1, int32_t c2) const
- {
- int32_t dc01 = c1 - c0;
- int32_t dc02 = c2 - c0;
- const int A = gglClz(abs(c0));
- const int B = gglClz(abs(dc01)|abs(dc02));
- const int scale = min(A, B - m_scale) - 2;
- if (scale >= 0) {
- c0 <<= scale;
- dc01 <<= scale;
- dc02 <<= scale;
- } else {
- c0 >>= -scale;
- dc01 >>= -scale;
- dc02 >>= -scale;
- }
- const int s = m_area_scale;
- int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s);
- int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s);
- int32_t c = c0 - (gglMulAddx(dcdx, m_x0,
- gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS));
- it[0] = c;
- it[1] = dcdx;
- it[2] = dcdy;
- return scale;
- }
- void compute_iterators_t::iterators1616(GGLfixed* it,
- GGLfixed c0, GGLfixed c1, GGLfixed c2) const
- {
- const GGLfixed dc01 = c1 - c0;
- const GGLfixed dc02 = c2 - c0;
- // 16.16 x 16.16 == 32.32 --> 16.16
- const int s = m_area_scale;
- int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s);
- int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s);
- int32_t c = c0 - (gglMulAddx(dcdx, m_x0,
- gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS));
- it[0] = c;
- it[1] = dcdx;
- it[2] = dcdy;
- }
- void compute_iterators_t::iterators0032(int64_t* it,
- int32_t c0, int32_t c1, int32_t c2) const
- {
- const int s = m_area_scale - 16;
- int32_t dc01 = (c1 - c0)>>s;
- int32_t dc02 = (c2 - c0)>>s;
- // 16.16 x 16.16 == 32.32
- int64_t dcdx = gglMulii(dc01, m_dy02) + gglMulii(dc02, m_dy10);
- int64_t dcdy = gglMulii(dc02, m_dx01) + gglMulii(dc01, m_dx20);
- it[ 0] = (c0<<16) - ((dcdx*m_x0 + dcdy*m_y0)>>4);
- it[ 1] = dcdx;
- it[ 2] = dcdy;
- }
- #if defined(__arm__) && !defined(__thumb__)
- inline void compute_iterators_t::iterators0032(int32_t* it,
- int32_t c0, int32_t c1, int32_t c2) const
- {
- ::iterators0032(this, it, c0, c1, c2);
- }
- #else
- void compute_iterators_t::iterators0032(int32_t* it,
- int32_t c0, int32_t c1, int32_t c2) const
- {
- int64_t it64[3];
- iterators0032(it64, c0, c1, c2);
- it[0] = it64[0];
- it[1] = it64[1];
- it[2] = it64[2];
- }
- #endif
- // ----------------------------------------------------------------------------
- static inline int32_t clampZ(GLfixed z) CONST;
- int32_t clampZ(GLfixed z) {
- z = (z & ~(z>>31));
- if (z >= 0x10000)
- z = 0xFFFF;
- return z;
- }
- static __attribute__((noinline))
- void fetch_texcoord_impl(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- vertex_t* const vtx[3] = { v0, v1, v2 };
- array_t const * const texcoordArray = c->arrays.texture;
-
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- if (!(c->rasterizer.state.texture[i].enable))
- continue;
-
- for (int j=0 ; j<3 ; j++) {
- vertex_t* const v = vtx[j];
- if (v->flags & vertex_t::TT)
- continue;
- // NOTE: here we could compute automatic texgen
- // such as sphere/cube maps, instead of fetching them
- // from the textcoord array.
- vec4_t& coords = v->texture[i];
- const GLubyte* tp = texcoordArray[i].element(
- v->index & vertex_cache_t::INDEX_MASK);
- texcoordArray[i].fetch(c, coords.v, tp);
- // transform texture coordinates...
- coords.Q = 0x10000;
- const transform_t& tr = c->transforms.texture[i].transform;
- if (ggl_unlikely(tr.ops)) {
- c->arrays.tex_transform[i](&tr, &coords, &coords);
- }
- // divide by Q
- const GGLfixed q = coords.Q;
- if (ggl_unlikely(q != 0x10000)) {
- const int32_t qinv = gglRecip28(q);
- coords.S = gglMulx(coords.S, qinv, 28);
- coords.T = gglMulx(coords.T, qinv, 28);
- }
- }
- }
- v0->flags |= vertex_t::TT;
- v1->flags |= vertex_t::TT;
- v2->flags |= vertex_t::TT;
- }
- inline void fetch_texcoord(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- const uint32_t enables = c->rasterizer.state.enables;
- if (!(enables & GGL_ENABLE_TMUS))
- return;
- // Fetch & transform texture coordinates...
- if (ggl_likely(v0->flags & v1->flags & v2->flags & vertex_t::TT)) {
- // already done for all three vertices, bail...
- return;
- }
- fetch_texcoord_impl(c, v0, v1, v2);
- }
- // ----------------------------------------------------------------------------
- #if 0
- #pragma mark -
- #pragma mark Point
- #endif
- void primitive_nop_point(ogles_context_t*, vertex_t*) {
- }
- void primitive_point(ogles_context_t* c, vertex_t* v)
- {
- // lighting & clamping...
- const uint32_t enables = c->rasterizer.state.enables;
- if (ggl_unlikely(!(v->flags & vertex_t::LIT))) {
- if (c->lighting.enable) {
- c->lighting.lightVertex(c, v);
- } else {
- v->flags |= vertex_t::LIT;
- const GLvoid* cp = c->arrays.color.element(
- v->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v->color.v, cp);
- }
- if (enables & GGL_ENABLE_FOG) {
- v->fog = c->fog.fog(c, v->eye.z);
- }
- }
- // XXX: we don't need to do that each-time
- // if color array and lighting not enabled
- c->rasterizer.procs.color4xv(c, v->color.v);
- // XXX: look into ES point-sprite extension
- if (enables & GGL_ENABLE_TMUS) {
- fetch_texcoord(c, v,v,v);
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- if (!c->rasterizer.state.texture[i].enable)
- continue;
- int32_t itt[8];
- itt[1] = itt[2] = itt[4] = itt[5] = 0;
- itt[6] = itt[7] = 16; // XXX: check that
- if (c->rasterizer.state.texture[i].s_wrap == GGL_CLAMP) {
- int width = c->textures.tmu[i].texture->surface.width;
- itt[0] = v->texture[i].S * width;
- itt[6] = 0;
- }
- if (c->rasterizer.state.texture[i].t_wrap == GGL_CLAMP) {
- int height = c->textures.tmu[i].texture->surface.height;
- itt[3] = v->texture[i].T * height;
- itt[7] = 0;
- }
- c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
- }
- }
-
- if (enables & GGL_ENABLE_DEPTH_TEST) {
- int32_t itz[3];
- itz[0] = clampZ(v->window.z) * 0x00010001;
- itz[1] = itz[2] = 0;
- c->rasterizer.procs.zGrad3xv(c, itz);
- }
- if (enables & GGL_ENABLE_FOG) {
- GLfixed itf[3];
- itf[0] = v->fog;
- itf[1] = itf[2] = 0;
- c->rasterizer.procs.fogGrad3xv(c, itf);
- }
- // Render our point...
- c->rasterizer.procs.pointx(c, v->window.v, c->point.size);
- }
- // ----------------------------------------------------------------------------
- #if 0
- #pragma mark -
- #pragma mark Line
- #endif
- void primitive_nop_line(ogles_context_t*, vertex_t*, vertex_t*) {
- }
- void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1)
- {
- // get texture coordinates
- fetch_texcoord(c, v0, v1, v1);
- // light/shade the vertices first (they're copied below)
- c->lighting.lightTriangle(c, v0, v1, v1);
- // clip the line if needed
- if (ggl_unlikely((v0->flags | v1->flags) & vertex_t::CLIP_ALL)) {
- unsigned int count = clip_line(c, v0, v1);
- if (ggl_unlikely(count == 0))
- return;
- }
- // compute iterators...
- const uint32_t enables = c->rasterizer.state.enables;
- const uint32_t mask = GGL_ENABLE_TMUS |
- GGL_ENABLE_SMOOTH |
- GGL_ENABLE_W |
- GGL_ENABLE_FOG |
- GGL_ENABLE_DEPTH_TEST;
- if (ggl_unlikely(enables & mask)) {
- c->lerp.initLine(v0, v1);
- lerp_triangle(c, v0, v1, v0);
- }
- // render our line
- c->rasterizer.procs.linex(c, v0->window.v, v1->window.v, c->line.width);
- }
- // ----------------------------------------------------------------------------
- #if 0
- #pragma mark -
- #pragma mark Triangle
- #endif
- void primitive_nop_triangle(ogles_context_t* /*c*/,
- vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* /*v2*/) {
- }
- void primitive_clip_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- uint32_t cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL;
- if (ggl_likely(!cc)) {
- // code below must be as optimized as possible, this is the
- // common code path.
- // This triangle is not clipped, test if it's culled
- // unclipped triangle...
- c->lerp.initTriangle(v0, v1, v2);
- if (cull_triangle(c, v0, v1, v2))
- return; // culled!
- // Fetch all texture coordinates if needed
- fetch_texcoord(c, v0, v1, v2);
- // light (or shade) our triangle!
- c->lighting.lightTriangle(c, v0, v1, v2);
- triangle(c, v0, v1, v2);
- return;
- }
- // The assumption here is that we're not going to clip very often,
- // and even more rarely will we clip a triangle that ends up
- // being culled out. So it's okay to light the vertices here, even though
- // in a few cases we won't render the triangle (if culled).
- // Fetch texture coordinates...
- fetch_texcoord(c, v0, v1, v2);
- // light (or shade) our triangle!
- c->lighting.lightTriangle(c, v0, v1, v2);
- clip_triangle(c, v0, v1, v2);
- }
- // -----------------------------------------------------------------------
- void triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- // compute iterators...
- const uint32_t enables = c->rasterizer.state.enables;
- const uint32_t mask = GGL_ENABLE_TMUS |
- GGL_ENABLE_SMOOTH |
- GGL_ENABLE_W |
- GGL_ENABLE_FOG |
- GGL_ENABLE_DEPTH_TEST;
- if (ggl_likely(enables & mask))
- lerp_triangle(c, v0, v1, v2);
- c->rasterizer.procs.trianglex(c, v0->window.v, v1->window.v, v2->window.v);
- }
- void lerp_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- const uint32_t enables = c->rasterizer.state.enables;
- c->lerp.initLerp(v0, enables);
- // set up texture iterators
- if (enables & GGL_ENABLE_TMUS) {
- if (enables & GGL_ENABLE_W) {
- lerp_texcoords_w(c, v0, v1, v2);
- } else {
- lerp_texcoords(c, v0, v1, v2);
- }
- }
- // set up the color iterators
- const compute_iterators_t& lerp = c->lerp;
- if (enables & GGL_ENABLE_SMOOTH) {
- GLfixed itc[12];
- for (int i=0 ; i<4 ; i++) {
- const GGLcolor c0 = v0->color.v[i] * 255;
- const GGLcolor c1 = v1->color.v[i] * 255;
- const GGLcolor c2 = v2->color.v[i] * 255;
- lerp.iterators1616(&itc[i*3], c0, c1, c2);
- }
- c->rasterizer.procs.colorGrad12xv(c, itc);
- }
- if (enables & GGL_ENABLE_DEPTH_TEST) {
- int32_t itz[3];
- const int32_t v0z = clampZ(v0->window.z);
- const int32_t v1z = clampZ(v1->window.z);
- const int32_t v2z = clampZ(v2->window.z);
- if (ggl_unlikely(c->polygonOffset.enable)) {
- const int32_t units = (c->polygonOffset.units << 16);
- const GLfixed factor = c->polygonOffset.factor;
- if (factor) {
- int64_t itz64[3];
- lerp.iterators0032(itz64, v0z, v1z, v2z);
- int64_t maxDepthSlope = max(itz64[1], itz64[2]);
- itz[0] = uint32_t(itz64[0])
- + uint32_t((maxDepthSlope*factor)>>16) + units;
- itz[1] = uint32_t(itz64[1]);
- itz[2] = uint32_t(itz64[2]);
- } else {
- lerp.iterators0032(itz, v0z, v1z, v2z);
- itz[0] += units;
- }
- } else {
- lerp.iterators0032(itz, v0z, v1z, v2z);
- }
- c->rasterizer.procs.zGrad3xv(c, itz);
- }
- if (ggl_unlikely(enables & GGL_ENABLE_FOG)) {
- GLfixed itf[3];
- lerp.iterators1616(itf, v0->fog, v1->fog, v2->fog);
- c->rasterizer.procs.fogGrad3xv(c, itf);
- }
- }
- static inline
- int compute_lod(ogles_context_t* c, int i,
- int32_t s0, int32_t t0, int32_t s1, int32_t t1, int32_t s2, int32_t t2)
- {
- // Compute mipmap level / primitive
- // rho = sqrt( texelArea / area )
- // lod = log2( rho )
- // lod = log2( texelArea / area ) / 2
- // lod = (log2( texelArea ) - log2( area )) / 2
- const compute_iterators_t& lerp = c->lerp;
- const GGLcoord area = abs(lerp.area());
- const int w = c->textures.tmu[i].texture->surface.width;
- const int h = c->textures.tmu[i].texture->surface.height;
- const int shift = 16 + (16 - TRI_FRACTION_BITS);
- int32_t texelArea = abs( gglMulx(s1-s0, t2-t0, shift) -
- gglMulx(s2-s0, t1-t0, shift) )*w*h;
- int log2TArea = (32-TRI_FRACTION_BITS -1) - gglClz(texelArea);
- int log2Area = (32-TRI_FRACTION_BITS*2-1) - gglClz(area);
- int lod = (log2TArea - log2Area + 1) >> 1;
- return lod;
- }
- void lerp_texcoords(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- const compute_iterators_t& lerp = c->lerp;
- int32_t itt[8] __attribute__((aligned(16)));
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- const texture_t& tmu = c->rasterizer.state.texture[i];
- if (!tmu.enable)
- continue;
- // compute the jacobians using block floating-point
- int32_t s0 = v0->texture[i].S;
- int32_t t0 = v0->texture[i].T;
- int32_t s1 = v1->texture[i].S;
- int32_t t1 = v1->texture[i].T;
- int32_t s2 = v2->texture[i].S;
- int32_t t2 = v2->texture[i].T;
- const GLenum min_filter = c->textures.tmu[i].texture->min_filter;
- if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) {
- int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2);
- c->rasterizer.procs.bindTextureLod(c, i,
- &c->textures.tmu[i].texture->mip(lod));
- }
- // premultiply (s,t) when clampling
- if (tmu.s_wrap == GGL_CLAMP) {
- const int width = tmu.surface.width;
- s0 *= width;
- s1 *= width;
- s2 *= width;
- }
- if (tmu.t_wrap == GGL_CLAMP) {
- const int height = tmu.surface.height;
- t0 *= height;
- t1 *= height;
- t2 *= height;
- }
- itt[6] = -lerp.iteratorsScale(itt+0, s0, s1, s2);
- itt[7] = -lerp.iteratorsScale(itt+3, t0, t1, t2);
- c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
- }
- }
- void lerp_texcoords_w(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- const compute_iterators_t& lerp = c->lerp;
- int32_t itt[8] __attribute__((aligned(16)));
- int32_t itw[3];
- // compute W's scale to 2.30
- int32_t w0 = v0->window.w;
- int32_t w1 = v1->window.w;
- int32_t w2 = v2->window.w;
- int wscale = 32 - gglClz(w0|w1|w2);
- // compute the jacobian using block floating-point
- int sc = lerp.iteratorsScale(itw, w0, w1, w2);
- sc += wscale - 16;
- c->rasterizer.procs.wGrad3xv(c, itw);
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- const texture_t& tmu = c->rasterizer.state.texture[i];
- if (!tmu.enable)
- continue;
- // compute the jacobians using block floating-point
- int32_t s0 = v0->texture[i].S;
- int32_t t0 = v0->texture[i].T;
- int32_t s1 = v1->texture[i].S;
- int32_t t1 = v1->texture[i].T;
- int32_t s2 = v2->texture[i].S;
- int32_t t2 = v2->texture[i].T;
- const GLenum min_filter = c->textures.tmu[i].texture->min_filter;
- if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) {
- int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2);
- c->rasterizer.procs.bindTextureLod(c, i,
- &c->textures.tmu[i].texture->mip(lod));
- }
- // premultiply (s,t) when clampling
- if (tmu.s_wrap == GGL_CLAMP) {
- const int width = tmu.surface.width;
- s0 *= width;
- s1 *= width;
- s2 *= width;
- }
- if (tmu.t_wrap == GGL_CLAMP) {
- const int height = tmu.surface.height;
- t0 *= height;
- t1 *= height;
- t2 *= height;
- }
- s0 = gglMulx(s0, w0, wscale);
- t0 = gglMulx(t0, w0, wscale);
- s1 = gglMulx(s1, w1, wscale);
- t1 = gglMulx(t1, w1, wscale);
- s2 = gglMulx(s2, w2, wscale);
- t2 = gglMulx(t2, w2, wscale);
- itt[6] = sc - lerp.iteratorsScale(itt+0, s0, s1, s2);
- itt[7] = sc - lerp.iteratorsScale(itt+3, t0, t1, t2);
- c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
- }
- }
- static inline
- bool cull_triangle(ogles_context_t* c, vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* /*v2*/)
- {
- if (ggl_likely(c->cull.enable)) {
- const GLenum winding = (c->lerp.area() > 0) ? GL_CW : GL_CCW;
- const GLenum face = (winding == c->cull.frontFace) ? GL_FRONT : GL_BACK;
- if (face == c->cull.cullFace)
- return true; // culled!
- }
- return false;
- }
- static inline
- GLfixed frustumPlaneDist(int plane, const vec4_t& s)
- {
- const GLfixed d = s.v[ plane >> 1 ];
- return ((plane & 1) ? (s.w - d) : (s.w + d));
- }
- static inline
- int32_t clipDivide(GLfixed a, GLfixed b) {
- // returns a 4.28 fixed-point
- return gglMulDivi(1LU<<28, a, b);
- }
- void clip_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
- {
- uint32_t all_cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL;
- vertex_t *p0, *p1, *p2;
- const int MAX_CLIPPING_PLANES = 6 + OGLES_MAX_CLIP_PLANES;
- const int MAX_VERTICES = 3;
- // Temporary buffer to hold the new vertices. Each plane can add up to
- // two new vertices (because the polygon is convex).
- // We need one extra element, to handle an overflow case when
- // the polygon degenerates into something non convex.
- vertex_t buffer[MAX_CLIPPING_PLANES * 2 + 1]; // ~3KB
- vertex_t* buf = buffer;
- // original list of vertices (polygon to clip, in fact this
- // function works with an arbitrary polygon).
- vertex_t* in[3] = { v0, v1, v2 };
-
- // output lists (we need 2, which we use back and forth)
- // (maximum outpout list's size is MAX_CLIPPING_PLANES + MAX_VERTICES)
- // 2 more elements for overflow when non convex polygons.
- vertex_t* out[2][MAX_CLIPPING_PLANES + MAX_VERTICES + 2];
- unsigned int outi = 0;
-
- // current input list
- vertex_t** ivl = in;
- // 3 input vertices, 0 in the output list, first plane
- unsigned int ic = 3;
- // User clip-planes first, the clipping is always done in eye-coordinate
- // this is basically the same algorithm than for the view-volume
- // clipping, except for the computation of the distance (vertex, plane)
- // and the fact that we need to compute the eye-coordinates of each
- // new vertex we create.
-
- if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL))
- {
- unsigned int plane = 0;
- uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8;
- do {
- if (cc & 1) {
- // pointers to our output list (head and current)
- vertex_t** const ovl = &out[outi][0];
- vertex_t** output = ovl;
- unsigned int oc = 0;
- unsigned int sentinel = 0;
- // previous vertex, compute distance to the plane
- vertex_t* s = ivl[ic-1];
- const vec4_t& equation = c->clipPlanes.plane[plane].equation;
- GLfixed sd = dot4(equation.v, s->eye.v);
- // clip each vertex against this plane...
- for (unsigned int i=0 ; i<ic ; i++) {
- vertex_t* p = ivl[i];
- const GLfixed pd = dot4(equation.v, p->eye.v);
- if (sd >= 0) {
- if (pd >= 0) {
- // both inside
- *output++ = p;
- oc++;
- } else {
- // s inside, p outside (exiting)
- const GLfixed t = clipDivide(sd, sd-pd);
- c->arrays.clipEye(c, buf, t, p, s);
- *output++ = buf++;
- oc++;
- if (++sentinel >= 3)
- return; // non-convex polygon!
- }
- } else {
- if (pd >= 0) {
- // s outside (entering)
- if (pd) {
- const GLfixed t = clipDivide(pd, pd-sd);
- c->arrays.clipEye(c, buf, t, s, p);
- *output++ = buf++;
- oc++;
- if (++sentinel >= 3)
- return; // non-convex polygon!
- }
- *output++ = p;
- oc++;
- } else {
- // both outside
- }
- }
- s = p;
- sd = pd;
- }
- // output list become the new input list
- if (oc<3)
- return; // less than 3 vertices left? we're done!
- ivl = ovl;
- ic = oc;
- outi = 1-outi;
- }
- cc >>= 1;
- plane++;
- } while (cc);
- }
- // frustum clip-planes
- if (all_cc & vertex_t::FRUSTUM_CLIP_ALL)
- {
- unsigned int plane = 0;
- uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL;
- do {
- if (cc & 1) {
- // pointers to our output list (head and current)
- vertex_t** const ovl = &out[outi][0];
- vertex_t** output = ovl;
- unsigned int oc = 0;
- unsigned int sentinel = 0;
- // previous vertex, compute distance to the plane
- vertex_t* s = ivl[ic-1];
- GLfixed sd = frustumPlaneDist(plane, s->clip);
- // clip each vertex against this plane...
- for (unsigned int i=0 ; i<ic ; i++) {
- vertex_t* p = ivl[i];
- const GLfixed pd = frustumPlaneDist(plane, p->clip);
- if (sd >= 0) {
- if (pd >= 0) {
- // both inside
- *output++ = p;
- oc++;
- } else {
- // s inside, p outside (exiting)
- const GLfixed t = clipDivide(sd, sd-pd);
- c->arrays.clipVertex(c, buf, t, p, s);
- *output++ = buf++;
- oc++;
- if (++sentinel >= 3)
- return; // non-convex polygon!
- }
- } else {
- if (pd >= 0) {
- // s outside (entering)
- if (pd) {
- const GLfixed t = clipDivide(pd, pd-sd);
- c->arrays.clipVertex(c, buf, t, s, p);
- *output++ = buf++;
- oc++;
- if (++sentinel >= 3)
- return; // non-convex polygon!
- }
- *output++ = p;
- oc++;
- } else {
- // both outside
- }
- }
- s = p;
- sd = pd;
- }
- // output list become the new input list
- if (oc<3)
- return; // less than 3 vertices left? we're done!
- ivl = ovl;
- ic = oc;
- outi = 1-outi;
- }
- cc >>= 1;
- plane++;
- } while (cc);
- }
-
- // finally we can render our triangles...
- p0 = ivl[0];
- p1 = ivl[1];
- for (unsigned int i=2 ; i<ic ; i++) {
- p2 = ivl[i];
- c->lerp.initTriangle(p0, p1, p2);
- if (cull_triangle(c, p0, p1, p2)) {
- p1 = p2;
- continue; // culled!
- }
- triangle(c, p0, p1, p2);
- p1 = p2;
- }
- }
- unsigned int clip_line(ogles_context_t* c, vertex_t* s, vertex_t* p)
- {
- const uint32_t all_cc = (s->flags | p->flags) & vertex_t::CLIP_ALL;
- if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL))
- {
- unsigned int plane = 0;
- uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8;
- do {
- if (cc & 1) {
- const vec4_t& equation = c->clipPlanes.plane[plane].equation;
- const GLfixed sd = dot4(equation.v, s->eye.v);
- const GLfixed pd = dot4(equation.v, p->eye.v);
- if (sd >= 0) {
- if (pd >= 0) {
- // both inside
- } else {
- // s inside, p outside (exiting)
- const GLfixed t = clipDivide(sd, sd-pd);
- c->arrays.clipEye(c, p, t, p, s);
- }
- } else {
- if (pd >= 0) {
- // s outside (entering)
- if (pd) {
- const GLfixed t = clipDivide(pd, pd-sd);
- c->arrays.clipEye(c, s, t, s, p);
- }
- } else {
- // both outside
- return 0;
- }
- }
- }
- cc >>= 1;
- plane++;
- } while (cc);
- }
- // frustum clip-planes
- if (all_cc & vertex_t::FRUSTUM_CLIP_ALL)
- {
- unsigned int plane = 0;
- uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL;
- do {
- if (cc & 1) {
- const GLfixed sd = frustumPlaneDist(plane, s->clip);
- const GLfixed pd = frustumPlaneDist(plane, p->clip);
- if (sd >= 0) {
- if (pd >= 0) {
- // both inside
- } else {
- // s inside, p outside (exiting)
- const GLfixed t = clipDivide(sd, sd-pd);
- c->arrays.clipVertex(c, p, t, p, s);
- }
- } else {
- if (pd >= 0) {
- // s outside (entering)
- if (pd) {
- const GLfixed t = clipDivide(pd, pd-sd);
- c->arrays.clipVertex(c, s, t, s, p);
- }
- } else {
- // both outside
- return 0;
- }
- }
- }
- cc >>= 1;
- plane++;
- } while (cc);
- }
- return 2;
- }
- }; // namespace android
|