|
| 1 | +#import "CCTexture.h" |
| 2 | +#import "CCNode_Private.h" |
| 3 | +#import "CCSprite_Private.h" |
| 4 | +#import "CCRenderer_Private.h" |
| 5 | +#import "CCShader_Private.h" |
| 6 | + |
| 7 | + |
| 8 | +@implementation CCNode(NoARC) |
| 9 | + |
| 10 | +static inline GLKMatrix4 |
| 11 | +CCNodeTransform(CCNode *node, GLKMatrix4 parentTransform) |
| 12 | +{ |
| 13 | + CGAffineTransform t = [node nodeToParentTransform]; |
| 14 | + float z = node->_vertexZ; |
| 15 | + |
| 16 | + // Convert to 4x4 column major GLK matrix. |
| 17 | + return GLKMatrix4Multiply(parentTransform, GLKMatrix4Make( |
| 18 | + t.a, t.b, 0.0f, 0.0f, |
| 19 | + t.c, t.d, 0.0f, 0.0f, |
| 20 | + 0.0f, 0.0f, 1.0f, 0.0f, |
| 21 | + t.tx, t.ty, z, 1.0f |
| 22 | + )); |
| 23 | +} |
| 24 | + |
| 25 | +-(GLKMatrix4)transform:(const GLKMatrix4 *)parentTransform |
| 26 | +{ |
| 27 | + return CCNodeTransform(self, *parentTransform); |
| 28 | +} |
| 29 | + |
| 30 | +-(void) visit:(CCRenderer *)renderer parentTransform:(const GLKMatrix4 *)parentTransform |
| 31 | +{ |
| 32 | + // quick return if not visible. children won't be drawn. |
| 33 | + if (!_visible) return; |
| 34 | + |
| 35 | + [self sortAllChildren]; |
| 36 | + |
| 37 | + GLKMatrix4 transform = CCNodeTransform(self, *parentTransform); |
| 38 | + BOOL drawn = NO; |
| 39 | + |
| 40 | + for(CCNode *child in _children){ |
| 41 | + if(!drawn && child.zOrder >= 0){ |
| 42 | + [self draw:renderer transform:&transform]; |
| 43 | + drawn = YES; |
| 44 | + } |
| 45 | + |
| 46 | + [child visit:renderer parentTransform:&transform]; |
| 47 | + } |
| 48 | + |
| 49 | + if(!drawn) [self draw:renderer transform:&transform]; |
| 50 | + |
| 51 | + // reset for next frame |
| 52 | + _orderOfArrival = 0; |
| 53 | +} |
| 54 | + |
| 55 | +@end |
| 56 | + |
| 57 | + |
| 58 | +@implementation CCSprite(NoARC) |
| 59 | + |
| 60 | +static inline void |
| 61 | +EnqueueTriangles(CCSprite *self, CCRenderer *renderer, const GLKMatrix4 *transform) |
| 62 | +{ |
| 63 | + CCRenderState *state = self->_renderState ?: self.renderState; |
| 64 | + CCRenderBuffer buffer = [renderer enqueueTriangles:2 andVertexes:4 withState:state globalSortOrder:0]; |
| 65 | + |
| 66 | + CCRenderBufferSetVertex(buffer, 0, CCVertexApplyTransform(self->_verts.bl, transform)); |
| 67 | + CCRenderBufferSetVertex(buffer, 1, CCVertexApplyTransform(self->_verts.br, transform)); |
| 68 | + CCRenderBufferSetVertex(buffer, 2, CCVertexApplyTransform(self->_verts.tr, transform)); |
| 69 | + CCRenderBufferSetVertex(buffer, 3, CCVertexApplyTransform(self->_verts.tl, transform)); |
| 70 | + |
| 71 | + CCRenderBufferSetTriangle(buffer, 0, 0, 1, 2); |
| 72 | + CCRenderBufferSetTriangle(buffer, 1, 0, 2, 3); |
| 73 | +} |
| 74 | + |
| 75 | +-(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform; |
| 76 | +{ |
| 77 | + if(!CCRenderCheckVisbility(transform, _vertexCenter, _vertexExtents)) return; |
| 78 | + |
| 79 | + if (_effect) |
| 80 | + { |
| 81 | + _effectRenderer.contentSize = self.contentSize; |
| 82 | + if ([self.effect prepareForRendering] == CCEffectPrepareSuccess) |
| 83 | + { |
| 84 | + // Preparing an effect for rendering can modify its uniforms |
| 85 | + // dictionary which means we need to reinitialize our copy of the |
| 86 | + // uniforms. |
| 87 | + [self updateShaderUniformsFromEffect]; |
| 88 | + } |
| 89 | + [_effectRenderer drawSprite:self withEffect:self.effect uniforms:_shaderUniforms renderer:renderer transform:transform]; |
| 90 | + } |
| 91 | + else |
| 92 | + { |
| 93 | + EnqueueTriangles(self, renderer, transform); |
| 94 | + } |
| 95 | + |
| 96 | +#if CC_SPRITE_DEBUG_DRAW |
| 97 | + const GLKVector2 zero = {{0, 0}}; |
| 98 | + const GLKVector4 white = {{1, 1, 1, 1}}; |
| 99 | + |
| 100 | + CCRenderBuffer debug = [renderer enqueueLines:4 andVertexes:4 withState:[CCRenderState debugColor] globalSortOrder:0]; |
| 101 | + CCRenderBufferSetVertex(debug, 0, (CCVertex){GLKMatrix4MultiplyVector4(*transform, _verts.bl.position), zero, zero, white}); |
| 102 | + CCRenderBufferSetVertex(debug, 1, (CCVertex){GLKMatrix4MultiplyVector4(*transform, _verts.br.position), zero, zero, white}); |
| 103 | + CCRenderBufferSetVertex(debug, 2, (CCVertex){GLKMatrix4MultiplyVector4(*transform, _verts.tr.position), zero, zero, white}); |
| 104 | + CCRenderBufferSetVertex(debug, 3, (CCVertex){GLKMatrix4MultiplyVector4(*transform, _verts.tl.position), zero, zero, white}); |
| 105 | + |
| 106 | + CCRenderBufferSetLine(debug, 0, 0, 1); |
| 107 | + CCRenderBufferSetLine(debug, 1, 1, 2); |
| 108 | + CCRenderBufferSetLine(debug, 2, 2, 3); |
| 109 | + CCRenderBufferSetLine(debug, 3, 3, 0); |
| 110 | +#endif |
| 111 | +} |
| 112 | + |
| 113 | +-(void)enqueueTriangles:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform |
| 114 | +{ |
| 115 | + EnqueueTriangles(self, renderer, transform); |
| 116 | +} |
| 117 | + |
| 118 | +@end |
| 119 | + |
| 120 | + |
| 121 | +@implementation CCRenderer(NoARC) |
| 122 | + |
| 123 | +-(CCRenderBuffer)enqueueTriangles:(NSUInteger)triangleCount andVertexes:(NSUInteger)vertexCount withState:(CCRenderState *)renderState globalSortOrder:(NSInteger)globalSortOrder; |
| 124 | +{ |
| 125 | + // Need to record the first vertex or element index before pushing more vertexes. |
| 126 | + size_t firstVertex = _vertexBuffer.count; |
| 127 | + size_t firstElement = _elementBuffer.count; |
| 128 | + |
| 129 | + size_t elementCount = 3*triangleCount; |
| 130 | + CCVertex *vertexes = CCGraphicsBufferPushElements(&_vertexBuffer, vertexCount, self); |
| 131 | + GLushort *elements = CCGraphicsBufferPushElements(&_elementBuffer, elementCount, self); |
| 132 | + |
| 133 | + CCRenderCommandDraw *previous = _lastDrawCommand; |
| 134 | + if(previous && previous->_renderState == renderState && previous->_globalSortOrder == globalSortOrder){ |
| 135 | + // Batch with the previous command. |
| 136 | + [previous batchElements:(GLsizei)elementCount]; |
| 137 | + } else { |
| 138 | + // Start a new command. |
| 139 | + CCRenderCommandDraw *command = [[CCRenderCommandDraw alloc] initWithMode:GL_TRIANGLES renderState:renderState first:(GLint)firstElement elements:(GLsizei)elementCount globalSortOrder:globalSortOrder]; |
| 140 | + [_queue addObject:command]; |
| 141 | + [command release]; |
| 142 | + |
| 143 | + _lastDrawCommand = command; |
| 144 | + } |
| 145 | + |
| 146 | + return (CCRenderBuffer){vertexes, elements, firstVertex}; |
| 147 | +} |
| 148 | + |
| 149 | +-(CCRenderBuffer)enqueueLines:(NSUInteger)lineCount andVertexes:(NSUInteger)vertexCount withState:(CCRenderState *)renderState globalSortOrder:(NSInteger)globalSortOrder; |
| 150 | +{ |
| 151 | + // Need to record the first vertex or element index before pushing more vertexes. |
| 152 | + size_t firstVertex = _vertexBuffer.count; |
| 153 | + size_t firstElement = _elementBuffer.count; |
| 154 | + |
| 155 | + size_t elementCount = 2*lineCount; |
| 156 | + CCVertex *vertexes = CCGraphicsBufferPushElements(&_vertexBuffer, vertexCount, self); |
| 157 | + GLushort *elements = CCGraphicsBufferPushElements(&_elementBuffer, elementCount, self); |
| 158 | + |
| 159 | + CCRenderCommandDraw *command = [[CCRenderCommandDraw alloc] initWithMode:GL_LINES renderState:renderState first:(GLint)firstElement elements:(GLsizei)elementCount globalSortOrder:globalSortOrder]; |
| 160 | + [_queue addObject:command]; |
| 161 | + [command release]; |
| 162 | + |
| 163 | + // Line drawing commands are currently intended for debugging and cannot be batched. |
| 164 | + _lastDrawCommand = nil; |
| 165 | + |
| 166 | + return(CCRenderBuffer){vertexes, elements, firstVertex}; |
| 167 | +} |
| 168 | + |
| 169 | +@end |
| 170 | + |
| 171 | + |
| 172 | +@implementation CCRenderer(NoARCPrivate) |
| 173 | + |
| 174 | +-(void)setRenderState:(CCRenderState *)renderState |
| 175 | +{ |
| 176 | + [self bindVAO:YES]; |
| 177 | + if(renderState == _renderState) return; |
| 178 | + |
| 179 | + glPushGroupMarkerEXT(0, "CCRenderer: Render State"); |
| 180 | + |
| 181 | + // Set the blending state. |
| 182 | + NSDictionary *blendOptions = renderState->_blendMode->_options; |
| 183 | + if(blendOptions != _blendOptions){ |
| 184 | + glInsertEventMarkerEXT(0, "Blending mode"); |
| 185 | + |
| 186 | + if(blendOptions == CCBLEND_DISABLED_OPTIONS){ |
| 187 | + if(_blendOptions != CCBLEND_DISABLED_OPTIONS) glDisable(GL_BLEND); |
| 188 | + } else { |
| 189 | + if(_blendOptions == nil || _blendOptions == CCBLEND_DISABLED_OPTIONS) glEnable(GL_BLEND); |
| 190 | + |
| 191 | + glBlendFuncSeparate( |
| 192 | + [blendOptions[CCBlendFuncSrcColor] unsignedIntValue], |
| 193 | + [blendOptions[CCBlendFuncDstColor] unsignedIntValue], |
| 194 | + [blendOptions[CCBlendFuncSrcAlpha] unsignedIntValue], |
| 195 | + [blendOptions[CCBlendFuncDstAlpha] unsignedIntValue] |
| 196 | + ); |
| 197 | + |
| 198 | + glBlendEquationSeparate( |
| 199 | + [blendOptions[CCBlendEquationColor] unsignedIntValue], |
| 200 | + [blendOptions[CCBlendEquationAlpha] unsignedIntValue] |
| 201 | + ); |
| 202 | + } |
| 203 | + |
| 204 | + _blendOptions = blendOptions; |
| 205 | + } |
| 206 | + |
| 207 | + // Bind the shader. |
| 208 | + CCShader *shader = renderState->_shader; |
| 209 | + if(shader != _shader){ |
| 210 | + glInsertEventMarkerEXT(0, "Shader"); |
| 211 | + |
| 212 | + glUseProgram(shader->_program); |
| 213 | + |
| 214 | + _shader = shader; |
| 215 | + _shaderUniforms = nil; |
| 216 | + } |
| 217 | + |
| 218 | + // Set the shader's uniform state. |
| 219 | + NSDictionary *shaderUniforms = renderState->_shaderUniforms; |
| 220 | + NSDictionary *globalShaderUniforms = _globalShaderUniforms; |
| 221 | + if(shaderUniforms != _shaderUniforms){ |
| 222 | + glInsertEventMarkerEXT(0, "Uniforms"); |
| 223 | + |
| 224 | + NSDictionary *setters = shader->_uniformSetters; |
| 225 | + for(NSString *uniformName in setters){ |
| 226 | + CCUniformSetter setter = setters[uniformName]; |
| 227 | + setter(self, shaderUniforms, globalShaderUniforms); |
| 228 | + } |
| 229 | + _shaderUniforms = shaderUniforms; |
| 230 | + } |
| 231 | + |
| 232 | + CC_CHECK_GL_ERROR_DEBUG(); |
| 233 | + glPopGroupMarkerEXT(); |
| 234 | + |
| 235 | + _renderState = renderState; |
| 236 | + return; |
| 237 | +} |
| 238 | + |
| 239 | +@end |
0 commit comments