首页 找课程 找学校 教育新闻 培训问答 课程大全

苏州其然软件开发培训

13013833891 预约试听 在线客服

您的位置: 首页 > 苏州培训 > 苏州其然软件开发培训 > web前端培训 > 太仓女生0基础学java有多难

太仓女生0基础学java有多难

班制:

周末班

[ 开班提醒 ]
上课地址:

苏州其然软件开发

活动倒计时
11: 59: 59
马上抢

课程介绍

太仓女生0基础学java有多难
教学的至高境界 分级教学

太仓女生0基础学java有多难

Java到 什么程度才能就业?

太仓女生0基础学java有多难

多年Java开发从业者:首先,这个问题主要问:自学Java编程技术,如果才 能找到一份Java编程的工作。按照现在的招聘标准来看,无论你去哪个公司面试,你只需要满足他们公司的需求就可以。

找到一份Java编程工作需要掌握的内容如下 :

首先是Javase作为Java**基本的学习 内容,不在多说。

然后是掌握Java的基本原理,因为做Java 编程开发必须学会Java,用到Java非常多,但是现在很多公司是不用去写原生的Java,但是如果你想成为一个厉害的Java开发者,Java必须从理论到实 际操作中都要非常得心应手。

现在公司是必须要求会用框架的,所以取代Java的就是jQuery,这是一个非 常简易的框架,学jQuery的时候你就会觉得它比Java好用的多。所以jQuery是你必须掌握的。

还有必须学一些框架,比如SpringMVC、Spring、Mybatis、Struts、Hibernate等等,这些就会难理解一些,但是公司是需要要求你会框架的,目前国内的公司应用SSH比 较多,建议至少学三个框架,这是找到工作的基本需求。

数据库技术是Java工作者必须掌握的技能常用就是Mysql。

Javaweb的内容还有html、css、jsp、Servlet等技术,这些都是现在找Java开发必须掌握的东西。

以上就是粗略的必须掌握的技术,如果你想找到一份Java开发的工作,上述 相关技术必须熟练掌握并且应用到项目中。

Java设计和编程思想课程介绍 


太仓女生0基础学java有多难

Java设计和编程思想

Java基础

环境搭建(包括Windows下和

Linux下的Java环境搭建)

Java语言基础

Java流程控制

Java常用类

Java面向对象

Java类与对象

介绍面向对象多态

接口与抽象类

Java高级

异常处理

I/O、JavaBean

反射

多线程

网络编程

泛型/Java集合类

Java与数据库

MySQL

ORACLE

JDBC开发与应用

Redis

课程优势

1.行业一线讲师讲解,深入浅出。

2.全面、完善的java课程体系,帮助学员更深更广的体验java魅力。

本阶段学习目标

1.精通java面向对象思想和基础语法。

2.熟练java中异常处理。

3.精通java中I/O操作。

4.掌握java中多线程操作。

5.精通java中集合类的使用。

6.掌握java中网络编程。

7.精通数据库/JDBC/redis/mysql的使用

本阶段学习效果

1.精通Java语言及其高级特性。

2.具备本地应用开发能力,能够开发一些本地软件,例如:聊天室,文件传 输助手等。

Cocos2d-x Sprite笔记


>

1.create

auto sPRite = Sprite::create("HelloWorld.png"); Sprite* Sprite::create(const std::string& filename) { Sprite *sprite = new (std::nothrow) Sprite(); if (sprite && sprite->initWithFile(filename)) { sprite->autorelease(); return sprite; } CC_SAFE_DELETE(sprite); return nullptr; } Sprite::Sprite(void) : _batchNode(nullptr) , _textureAtlas(nullptr) , _shouldBeHidden(false) , _texture(nullptr) , _spriteFrame(nullptr) , _insideBounds(true) { }

2.init

bool Sprite::initWithFile(const std::string& filename) { if (filename.empty()) { CCLOG("Call Sprite::initWithFile with blank resource filename."); return false; } _fileName = filename; _fileType = 0; Texture2D *texture = _director->getTextureCache()->addImage(filename); if (texture) { Rect rect = Rect::ZERO; rect.size = texture->getContentSize(); return initWithTexture(texture, rect); } // don t release here. // when load texture failed, it s better to get a "transparent" sprite then a crashed program // this->release(); return false; }

1)_director->getTextureCache()->addImage(filename):TextureCache用于管理texture的加载(另开一个线程) 2)rect.size = texture->getContentSize():用texture content size(像素为单位,window.size也是以像素为单位)作为Sprite的size,如果是一张1024X768的图片,则rect = (0,0,1024,768),这个rect会用来生成Sprite的顶点坐标,比如这个Rect的右上角对应的顶点坐标是(1024 / window.size.w, 768 / window.size.h)

bool Node::init() { return true; } bool Sprite::initWithTexture(Texture2D *texture, const Rect& rect, bool rotated) { bool result = false; if (Node::init()) { _batchNode = nullptr; _recursiveDirty = false; setDirty(false); _opacityModifyRGB = true; _blendFunc = BlendFunc::ALPHA_PREMULTipLIED; _flippedX = _flippedY = false; // default transform anchor: center setAnchorPoint(Vec2(0.5f, 0.5f)); // zwoptex default values _offsetPosition.setZero(); // clean the Quad memset(&_quad, 0, sizeof(_quad)); // Atlas: Color _quad.bl.colors = Color4B::WHITE; _quad.br.colors = Color4B::WHITE; _quad.tl.colors = Color4B::WHITE; _quad.tr.colors = Color4B::WHITE; // update texture (calls updateBlendFunc), set program but not set vertex attrib and uniform setTexture(texture); // set _quad, _texcoord setTextureRect(rect, rotated, rect.size); // by default use "Self Render". // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" setBatchNode(nullptr); result = true; } _recursiveDirty = true; setDirty(true); return result; }

0)_quad.bl.colors = Color4B::WHITE:默认4个角的颜色为白色 1)_flippedX = _flippedY = false:不需要flip,因为TexCoords按照未flip生成的(y轴向下,OpenGL坐标系y轴向上) 2)setAnchorPoint(Vec2(0.5f, 0.5f)):除了layer类,其他Node类锚点默认在正中间 3)_offsetPosition.setZero():Node的content size可能和texture size不一样,这样就会产生offset,一般offset都是0。因为使用texture的content size来设置Node的content size的,两者相等,所以没有offset。 4)setTexture(texture):设置texture,获取GLProgramState,加载编译所有的program,如果texture为nullptr,用一张白色的图片作为texture

void Sprite::setTexture(Texture2D *texture) { setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR__MVP, texture)); // If batchnode, then texture id should be the same CCASSERT(! _batchNode || (texture && texture->getName() == _batchNode->getTexture()->getName()), "CCSprite: Batched sprites should use the same texture as the batchnode"); // accept texture==nil as argument CCASSERT( !texture || dynamic_cast<Texture2D*>(texture), "setTexture expects a Texture2D. Invalid argument"); if (texture == nullptr) { // Gets the texture by key firstly. texture = _director->getTextureCache()->getTextureForKey(CC_2x2_WHITE_IMAGE_KEY); // If texture wasn t in cache, create it from RAW data. if (texture == nullptr) { Image* image = new (std::nothrow) Image(); bool isOK = image->initWithRawData(cc_2x2_white_image, sizeof(cc_2x2_white_image), 2, 2, 8); CC_UNUSED_PARAM(isOK); CCASSERT(isOK, "The 2x2 empty texture was created unsuccessfully."); texture = _director->getTextureCache()->addImage(image, CC_2x2_WHITE_IMAGE_KEY); CC_SAFE_RELEASE(image); } } if (!_batchNode && _texture != texture) { CC_SAFE_RETAIN(texture); CC_SAFE_RELEASE(_texture); _texture = texture; updateBlendFunc(); } }

5)setTextureRect(rect, rotated, rect.size):setTexCoords(左上为(0,0), 左下为(0.1),load image不flip,TexCoords实现flip)和setPosition(position没有变,左下为(0,0))

void Sprite::setTextureRect(const Rect& rect, bool rotated, const Size& untrimmedSize) { _rectRotated = rotated; setContentSize(untrimmedSize); setVertexRect(rect); setTextureCoords(rect); float relativeOffsetX = _unflippedOffsetPositionFromCenter.x; float relativeOffsetY = _unflippedOffsetPositionFromCenter.y; // issue #732 if (_flippedX) { relativeOffsetX = -relativeOffsetX; } if (_flippedY) { relativeOffsetY = -relativeOffsetY; } _offsetPosition.x = relativeOffsetX (_contentSize.width - _rect.size.width) / 2; _offsetPosition.y = relativeOffsetY (_contentSize.height - _rect.size.height) / 2; // rendering using batch node if (_batchNode) { // update dirty_, don t update recursiveDirty_ setDirty(true); } else { // self rendering // Atlas: Vertex float x1 = 0.0f _offsetPosition.x; float y1 = 0.0f _offsetPosition.y; float x2 = x1 _rect.size.width; float y2 = y1 _rect.size.height; // Don t update Z. _quad.bl.vertices.set(x1, y1, 0.0f); _quad.br.vertices.set(x2, y1, 0.0f); _quad.tl.vertices.set(x1, y2, 0.0f); _quad.tr.vertices.set(x2, y2, 0.0f); } _polyInfo.setQuad(&_quad); } void Node::setContentSize(const Size & size) { if (! size.equals(_contentSize)) { _contentSize = size; _anchorPointInPoints.set(_contentSize.width * _anchorPoint.x, _contentSize.height * _anchorPoint.y); _transformUpdated = _transformDirty = _inverseDirty = _contentSizeDirty = true; } } void Sprite::setVertexRect(const Rect& rect) { _rect = rect; } void Sprite::setTextureCoords(const Rect& rectInPoint) { Texture2D *tex = _batchNode ? _textureAtlas->getTexture() : _texture; if (tex == nullptr) { return; } auto rectInPixels = CC_RECT_POINTS_TO_PIXELS(rectInPoint); float atlasWidth = (float)tex->getPixelsWide(); float atlasHeight = (float)tex->getPixelsHigh(); float left, right, top, bottom; if (_rectRotated) { #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL left = (2*rectInPixels.origin.x 1)/(2*atlasWidth); right = left (rectInPixels.size.height*2-2)/(2*atlasWidth); top = (2*rectInPixels.origin.y 1)/(2*atlasHeight); bottom = top (rectInPixels.size.width*2-2)/(2*atlasHeight); #else left = rectInPixels.origin.x/atlasWidth; right = (rectInPixels.origin.x rectInPixels.size.height) / atlasWidth; top = rectInPixels.origin.y/atlasHeight; bottom = (rectInPixels.origin.y rectInPixels.size.width) / atlasHeight; #endif // CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL if (_flippedX) { std::swap(top, bottom); } if (_flippedY) { std::swap(left, right); } _quad.bl.texCoords.u = left; _quad.bl.texCoords.v = top; _quad.br.texCoords.u = left; _quad.br.texCoords.v = bottom; _quad.tl.texCoords.u = right; _quad.tl.texCoords.v = top; _quad.tr.texCoords.u = right; _quad.tr.texCoords.v = bottom; } else { #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL left = (2*rectInPixels.origin.x 1)/(2*atlasWidth); right = left (rectInPixels.size.width*2-2)/(2*atlasWidth); top = (2*rectInPixels.origin.y 1)/(2*atlasHeight); bottom = top (rectInPixels.size.height*2-2)/(2*atlasHeight); #else left = rectInPixels.origin.x/atlasWidth; right = (rectInPixels.origin.x rectInPixels.size.width) / atlasWidth; top = rectInPixels.origin.y/atlasHeight; bottom = (rectInPixels.origin.y rectInPixels.size.height) / atlasHeight; #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL if(_flippedX) { std::swap(left, right); } if(_flippedY) { std::swap(top, bottom); } _quad.bl.texCoords.u = left; _quad.bl.texCoords.v = bottom; _quad.br.texCoords.u = right; _quad.br.texCoords.v = bottom; _quad.tl.texCoords.u = left; _quad.tl.texCoords.v = top; _quad.tr.texCoords.u = right; _quad.tr.texCoords.v = top; } } /**The structure of Triangles. */ struct Triangles { /**Vertex data pointer.*/ V3F_C4B_T2F* verts; /**Index data pointer.*/ unsigned short* indices; /**The number of vertices.*/ int vertCount; /**The number of indices.*/ int indexCount; }; static unsigned short quadIndices[]={0,1,2, 3,2,1}; void PolygonInfo::setQuad(V3F_C4B_T2F_Quad *quad) { releaseVertsAndIndices(); isVertsOwner = false; triangles.indices = quadIndices; triangles.vertCount = 4; triangles.indexCount = 6; triangles.verts = (V3F_C4B_T2F*)quad; }

6)init之后,texture,position(未归一化,bl(0,0),br(0,1024),tl(0,768),tr(1024,768)),indices(预定义的{0,1,2, 3,2,1}),TexCoords(flip过的,bl(0,1),br(1,1),tl(0,0),tr(1,0))

3.setPosition

sprite->setPosition(Vec2(visibleSize / 2) origin); void Sprite::setPosition(const Vec2& pos) { Node::setPosition(pos); SET_DIRTY_RECURSIVELY(); } void Node::setPosition(float x, float y) { if (_position.x == x && _position.y == y) return; _position.x = x; _position.y = y; _transformUpdated = _transformDirty = _inverseDirty = true; _usingNormalizedPosition = false; }

1)这里的Position是用来生成translate的 2)与移动相关的Action修改的也是这个Position 3)如何由Position到Transform Matrix

const Mat4& Node::getNodeToParentTransform() const { if (_transformDirty) { // Translate values 0 float x = _position.x; float y = _position.y; float z = _positionZ; // _ignoreAnchorPointForPosition = false if (_ignoreAnchorPointForPosition) { x = _anchorPointInPoints.x; y = _anchorPointInPoints.y; } bool needsSkewMatrix = ( _skewX || _skewY ); Vec2 anchorPoint(_anchorPointInPoints.x * _scaleX, _anchorPointInPoints.y * _scaleY); // calculate real position 1 // get real translation if (! needsSkewMatrix && !_anchorPointInPoints.isZero()) { x = -anchorPoint.x; y = -anchorPoint.y; } // Build Transform Matrix = translation * rotation * scale Mat4 translation; // move to anchor point first, then rotate 2 // will restore after rotate Mat4::createTranslation(x anchorPoint.x, y anchorPoint.y, z, &translation); Mat4::createRotation(_rotationQuat, &_transform); if (_rotationZ_X != _rotationZ_Y) { // Rotation values // Change rotation code to handle X and Y // If we skew with the exact same value for both x and y then we re simply just rotating float radiansX = -CC_DEGREES_TO_RADIANS(_rotationZ_X); float radiansY = -CC_DEGREES_TO_RADIANS(_rotationZ_Y); float cx = cosf(radiansX); float sx = sinf(radiansX); float cy = cosf(radiansY); float sy = sinf(radiansY); float m0 = _transform.m[0], m1 = _transform.m[1], m4 = _transform.m[4], m5 = _transform.m[5], m8 = _transform.m[8], m9 = _transform.m[9]; _transform.m[0] = cy * m0 - sx * m1, _transform.m[4] = cy * m4 - sx * m5, _transform.m[8] = cy * m8 - sx * m9; _transform.m[1] = sy * m0 cx * m1, _transform.m[5] = sy * m4 cx * m5, _transform.m[9] = sy * m8 cx * m9; } _transform = translation * _transform; // move by (-anchorPoint.x, -anchorPoint.y, 0) after rotation 3 // restore position after rotate _transform.translate(-anchorPoint.x, -anchorPoint.y, 0); if (_scaleX != 1.f) { _transform.m[0] *= _scaleX, _transform.m[1] *= _scaleX, _transform.m[2] *= _scaleX; } if (_scaleY != 1.f) { _transform.m[4] *= _scaleY, _transform.m[5] *= _scaleY, _transform.m[6] *= _scaleY; } if (_scaleZ != 1.f) { _transform.m[8] *= _scaleZ, _transform.m[9] *= _scaleZ, _transform.m[10] *= _scaleZ; } // FIXME:: Try to inline skew // If skew is needed, apply skew and then anchor point if (needsSkewMatrix) { float skewMatArray[16] = { 1, (float)tanf(CC_DEGREES_TO_RADIANS(_skewY)), 0, 0, (float)tanf(CC_DEGREES_TO_RADIANS(_skewX)), 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; Mat4 skewMatrix(skewMatArray); _transform = _transform * skewMatrix; // adjust anchor point if (!_anchorPointInPoints.isZero()) { // FIXME:: Argh, Mat4 needs a "translate" method. // FIXME:: Although this is faster than multiplying a vec4 * mat4 _transform.m[12] = _transform.m[0] * -_anchorPointInPoints.x _transform.m[4] * -_anchorPointInPoints.y; _transform.m[13] = _transform.m[1] * -_anchorPointInPoints.x _transform.m[5] * -_anchorPointInPoints.y; } } } // only camera node need this maybe, get additional transform from scene s eyeTransform Matrix if (_additionalTransform) { // This is needed to support both Node::setNodeToParentTransform() and Node::setAdditionalTransform() // at the same time. The scenario is this: // at some point setNodeToParentTransform() is called. // and later setAdditionalTransform() is called every time. And since _transform // is being overwritten everyframe, _additionalTransform[1] is used to have a copy // of the last "_transform without _additionalTransform" if (_transformDirty) _additionalTransform[1] = _transform; if (_transformUpdated) _transform = _additionalTransform[1] * _additionalTransform[0]; } _transformDirty = _additionalTransformDirty = false; return _transform; }

4.visit

void Node::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags) { // quick return if not visible. children won t be drawn. if (!_visible) { return; } // set transform uint32_t flags = processParentFlags(parentTransform, parentFlags); // IMPORTANT: // To ease the migration to v3.0, we still support the Mat4 stack, // but it is deprecated and your code should not rely on it _director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); _director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform); bool visibleByCamera = isVisitableByVisitingCamera(); int i = 0; if(!_children.empty()) { sortAllChildren(); // draw children zOrder < 0 for( ; i < _children.size(); i ) { auto node = _children.at(i); if (node && node->_localZOrder < 0) node->visit(renderer, _modelViewTransform, flags); else break; } // self draw if (visibleByCamera) this->draw(renderer, _modelViewTransform, flags); for(auto it=_children.cbegin() i; it != _children.cend(); it) (*it)->visit(renderer, _modelViewTransform, flags); } else if (visibleByCamera) { this->draw(renderer, _modelViewTransform, flags); } _director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); // FIX ME: Why need to set _orderOfArrival to 0?? // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920 // reset for next frame // _orderOfArrival = 0; }

由Position get _modelViewTransform

uint32_t Node::processParentFlags(const Mat4& parentTransform, uint32_t parentFlags) { // _usingNormalizedPosition = false if(_usingNormalizedPosition) { CCASSERT(_parent, "setNormalizedPosition() doesn t work with orphan nodes"); if ((parentFlags & FLAGS_CONTENT_SIZE_DIRTY) || _normalizedPositionDirty) { auto& s = _parent->getContentSize(); _position.x = _normalizedPosition.x * s.width; _position.y = _normalizedPosition.y * s.height; _transformUpdated = _transformDirty = _inverseDirty = true; _normalizedPositionDirty = false; } } // Fixes Github issue #16100. Basically when having two cameras, one camera might set as dirty the // node that is not visited by it, and might affect certain calculations. Besides, it is faster to do this. if (!isVisitableByVisitingCamera()) return parentFlags; uint32_t flags = parentFlags; flags |= (_transformUpdated ? FLAGS_TRANSFORM_DIRTY : 0); flags |= (_contentSizeDirty ? FLAGS_CONTENT_SIZE_DIRTY : 0); // true if(flags & FLAGS_DIRTY_MASK) _modelViewTransform = this->transform(parentTransform); _transformUpdated = false; _contentSizeDirty = false; return flags; } Mat4 Node::transform(const Mat4& parentTransform) { return parentTransform * this->getNodeToParentTransform(); } const Mat4& Node::getNodeToParentTransform() const { if (_transformDirty) { // Translate values float x = _position.x; float y = _position.y; float z = _positionZ; // false if (_ignoreAnchorPointForPosition) { x = _anchorPointInPoints.x; y = _anchorPointInPoints.y; } bool needsSkewMatrix = ( _skewX || _skewY ); // (1024.0/2, 768.0/2) Vec2 anchorPoint(_anchorPointInPoints.x * _scaleX, _anchorPointInPoints.y * _scaleY); // calculate real position // not ignore AnchorPoint, calculate real translate values if (! needsSkewMatrix && !_anchorPointInPoints.isZero()) { x = -anchorPoint.x; y = -anchorPoint.y; } // Build Transform Matrix = translation * rotation * scale Mat4 translation; //move to anchor point first, then rotate 2 Mat4::createTranslation(x anchorPoint.x, y anchorPoint.y, z, &translation); Mat4::createRotation(_rotationQuat, &_transform); if (_rotationZ_X != _rotationZ_Y) { // Rotation values // Change rotation code to handle X and Y // If we skew with the exact same value for both x and y then we re simply just rotating float radiansX = -CC_DEGREES_TO_RADIANS(_rotationZ_X); float radiansY = -CC_DEGREES_TO_RADIANS(_rotationZ_Y); float cx = cosf(radiansX); float sx = sinf(radiansX); float cy = cosf(radiansY); float sy = sinf(radiansY); float m0 = _transform.m[0], m1 = _transform.m[1], m4 = _transform.m[4], m5 = _transform.m[5], m8 = _transform.m[8], m9 = _transform.m[9]; _transform.m[0] = cy * m0 - sx * m1, _transform.m[4] = cy * m4 - sx * m5, _transform.m[8] = cy * m8 - sx * m9; _transform.m[1] = sy * m0 cx * m1, _transform.m[5] = sy * m4 cx * m5, _transform.m[9] = sy * m8 cx * m9; } _transform = translation * _transform; //move by (-anchorPoint.x, -anchorPoint.y, 0) after rotation 3 _transform.translate(-anchorPoint.x, -anchorPoint.y, 0); if (_scaleX != 1.f) { _transform.m[0] *= _scaleX, _transform.m[1] *= _scaleX, _transform.m[2] *= _scaleX; } if (_scaleY != 1.f) { _transform.m[4] *= _scaleY, _transform.m[5] *= _scaleY, _transform.m[6] *= _scaleY; } if (_scaleZ != 1.f) { _transform.m[8] *= _scaleZ, _transform.m[9] *= _scaleZ, _transform.m[10] *= _scaleZ; } // FIXME:: Try to inline skew // If skew is needed, apply skew and then anchor point if (needsSkewMatrix) { float skewMatArray[16] = { 1, (float)tanf(CC_DEGREES_TO_RADIANS(_skewY)), 0, 0, (float)tanf(CC_DEGREES_TO_RADIANS(_skewX)), 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; Mat4 skewMatrix(skewMatArray); _transform = _transform * skewMatrix; // adjust anchor point if (!_anchorPointInPoints.isZero()) { // FIXME:: Argh, Mat4 needs a "translate" method. // FIXME:: Although this is faster than multiplying a vec4 * mat4 _transform.m[12] = _transform.m[0] * -_anchorPointInPoints.x _transform.m[4] * -_anchorPointInPoints.y; _transform.m[13] = _transform.m[1] * -_anchorPointInPoints.x _transform.m[5] * -_anchorPointInPoints.y; } } } // false if (_additionalTransform) { // This is needed to support both Node::setNodeToParentTransform() and Node::setAdditionalTransform() // at the same time. The scenario is this: // at some point setNodeToParentTransform() is called. // and later setAdditionalTransform() is called every time. And since _transform // is being overwritten everyframe, _additionalTransform[1] is used to have a copy // of the last "_transform without _additionalTransform" if (_transformDirty) _additionalTransform[1] = _transform; if (_transformUpdated) _transform = _additionalTransform[1] * _additionalTransform[0]; } _transformDirty = _additionalTransformDirty = false; return _transform; }

visit就是沿着Node树从root node把transform传递下去,如:scene的translate同样要apply到子children node,并且在apply transform后,按照树关系调用children node的draw()函数add command,Sprite添加TrianglesCommand

5.draw

void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) { if (_texture == nullptr) { return; } #if CC_USE_CULLING // Don t calculate the culling if the transform was not updated auto visitingCamera = Camera::getVisitingCamera(); auto defaultCamera = Camera::getDefaultCamera(); if (visitingCamera == defaultCamera) { _insideBounds = ((flags & FLAGS_TRANSFORM_DIRTY) || visitingCamera->isViewProjectionUpdated()) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds; } else { // XXX: this always return true since _insideBounds = renderer->checkVisibility(transform, _contentSize); } if(_insideBounds) #endif { _trianglesCommand.init(_globalZOrder, _texture, getGLProgramState(), _blendFunc, _polyInfo.triangles, transform, flags); renderer->addCommand(&_trianglesCommand); } } void TrianglesCommand::init(float globalOrder, GLuint textureID, GLProgramState* glProgramState, BlendFunc blendType, const Triangles& triangles,const Mat4& mv, uint32_t flags) { CCASSERT(glProgramState, "Invalid GLProgramState"); CCASSERT(glProgramState->getVertexAttribsFlags() == 0, "No custom attributes are supported in QuadCommand"); RenderCommand::init(globalOrder, mv, flags); _triangles = triangles; if(_triangles.indexCount % 3 != 0) { int count = _triangles.indexCount; _triangles.indexCount = count / 3 * 3; CCLOGERROR("Resize indexCount from %zd to %zd, size must be multiple times of 3", count, _triangles.indexCount); } _mv = mv; if( _textureID != textureID || _blendType.src != blendType.src || _blendType.dst != blendType.dst || _glProgramState != glProgramState || _glProgram != glProgramState->getGLProgram()) { _textureID = textureID; _blendType = blendType; _glProgramState = glProgramState; _glProgram = glProgramState->getGLProgram(); generateMaterialID(); } } void Renderer::addCommand(RenderCommand* command) { // renderQueue = 0, usual only one renderGroup int renderQueue =_commandGroupStack.top(); addCommand(command, renderQueue); } void Renderer::addCommand(RenderCommand* command, int renderQueue) { CCASSERT(!_isRendering, "Cannot add command while rendering"); CCASSERT(renderQueue >=0, "Invalid render queue"); CCASSERT(command->getType() != RenderCommand::Type::UNKWN_COMMAND, "Invalid Command Type"); // only have one render groups, but five commands array : GLOBALZ_NEG, OPAQUE_3D ... _renderGroups[renderQueue].push_back(command); } enum QUEUE_GROUP { /**Objects with globalZ smaller than 0.*/ GLOBALZ_NEG = 0, /**Opaque 3D objects with 0 globalZ.*/ OPAQUE_3D = 1, /**Transparent 3D objects with 0 globalZ.*/ TRANSPARENT_3D = 2, /**2D objects with 0 globalZ.*/ GLOBALZ_ZERO = 3, /**Objects with globalZ bigger than 0.*/ GLOBALZ_POS = 4, /**Max Queue Count*/ QUEUE_COUNT = 5, }; void RenderQueue::push_back(RenderCommand* command) { float z = command->getGlobalOrder(); if(z < 0) { _commands[QUEUE_GROUP::GLOBALZ_NEG].push_back(command); } else if(z > 0) { _commands[QUEUE_GROUP::GLOBALZ_POS].push_back(command); } else { if(command->is3D()) { if(command->isTransparent()) { _commands[QUEUE_GROUP::TRANSPARENT_3D].push_back(command); } else { _commands[QUEUE_GROUP::OPAQUE_3D].push_back(command); } } else { _commands[QUEUE_GROUP::GLOBALZ_ZERO].push_back(command); } } }

6.render

void Renderer::render() { //Uncomment this once everything is rendered by new renderer //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //TODO: setup camera or MVP _isRendering = true; if (_glViewAssigned) { //Process render commands //1. Sort render commands based on ID for (auto &renderqueue : _renderGroups) { // sort use zorder renderqueue.sort(); } // visitRenderQueue(_renderGroups[0]); } clean(); _isRendering = false; } void RenderQueue::sort() { // Don t sort _queue0, it already comes sorted std::sort(std::begin(_commands[QUEUE_GROUP::TRANSPARENT_3D]), std::end(_commands[QUEUE_GROUP::TRANSPARENT_3D]), compare3DCommand); std::sort(std::begin(_commands[QUEUE_GROUP::GLOBALZ_NEG]), std::end(_commands[QUEUE_GROUP::GLOBALZ_NEG]), compareRenderCommand); std::sort(std::begin(_commands[QUEUE_GROUP::GLOBALZ_POS]), std::end(_commands[QUEUE_GROUP::GLOBALZ_POS]), compareRenderCommand); } void Renderer::visitRenderQueue(RenderQueue& queue) { queue.saveRenderState(); // //Process Global-Z < 0 Objects // // //Process Opaque Object // // //Process 3D Transparent object // // //Process Global-Z = 0 Queue // const auto& zZeroQueue = queue.getSubQueue(RenderQueue::QUEUE_GROUP::GLOBALZ_ZERO); if (zZeroQueue.size() > 0) { // false if(_isDepthTestFor2D) { glEnable(GL_DEPTH_TEST); glDepthMask(true); glEnable(GL_BLEND); RenderState::StateBlock::_defaultState->setDepthTest(true); RenderState::StateBlock::_defaultState->setDepthWrite(true); RenderState::StateBlock::_defaultState->setBlend(true); } else { glDisable(GL_DEPTH_TEST); glDepthMask(false); glEnable(GL_BLEND); RenderState::StateBlock::_defaultState->setDepthTest(false); RenderState::StateBlock::_defaultState->setDepthWrite(false); RenderState::StateBlock::_defaultState->setBlend(true); } glDisable(GL_CULL_FACE); RenderState::StateBlock::_defaultState->setCullFace(false); for (auto it = zZeroQueue.cbegin(); it != zZeroQueue.cend(); it) { processRenderCommand(*it); } flush(); } // //Process Global-Z > 0 Queue // queue.restoreRenderState(); } void Renderer::processRenderCommand(RenderCommand* command) { auto commandType = command->getType(); if( RenderCommand::Type::TRIANGLES_COMMAND == commandType) { // flush other queues flush3D(); auto cmd = static_cast<TrianglesCommand*>(command); // flush own queue when buffer is full if(_filledVertex cmd->getVertexCount() > VBO_SIZE || _filledIndex cmd->getIndexCount() > INDEX_VBO_SIZE) { CCASSERT(cmd->getVertexCount()>= 0 && cmd->getVertexCount() < VBO_SIZE, "VBO for vertex is not big enough, please break the data down or use customized render command"); CCASSERT(cmd->getIndexCount()>= 0 && cmd->getIndexCount() < INDEX_VBO_SIZE, "VBO for index is not big enough, please break the data down or use customized render command"); drawBatchedTriangles(); } // queue it, draw when vector full or all cmd queued _queuedTriangleCommands.push_back(cmd); _filledIndex = cmd->getIndexCount(); _filledVertex = cmd->getVertexCount(); } } void Renderer::flush() { flush2D(); flush3D(); } void Renderer::flush2D() { flushTriangles(); } void Renderer::flushTriangles() { drawBatchedTriangles(); } void Renderer::fillVerticesAndIndices(const TrianglesCommand* cmd) { memcpy(&_verts[_filledVertex], cmd->getVertices(), sizeof(V3F_C4B_T2F) * cmd->getVertexCount()); // fill vertex, and convert them to world coordinates const Mat4& modelView = cmd->getModelView(); for(ssize_t i=0; i < cmd->getVertexCount(); i) { modelView.transformPoint(&(_verts[i _filledVertex].vertices)); } // fill index const unsigned short* indices = cmd->getIndices(); for(ssize_t i=0; i< cmd->getIndexCount(); i) { _indices[_filledIndex i] = _filledVertex indices[i]; } _filledVertex = cmd->getVertexCount(); _filledIndex = cmd->getIndexCount(); } void Renderer::drawBatchedTriangles() { if(_queuedTriangleCommands.empty()) return; CCGL_DEBUG_INSERT_EVENT_MARKER("RENDERER_BATCH_TRIANGLES"); _filledVertex = 0; _filledIndex = 0; /************** 1: Setup up vertices/indices *************/ _triBatchesToDraw[0].offset = 0; _triBatchesToDraw[0].indicesToDraw = 0; _triBatchesToDraw[0].cmd = nullptr; int batchesTotal = 0; int prevMaterialID = -1; bool firstCommand = true; for(auto it = std::begin(_queuedTriangleCommands); it != std::end(_queuedTriangleCommands); it) { const auto& cmd = *it; auto currentMaterialID = cmd->getMaterialID(); const bool batchable = !cmd->isSkipBatching(); // fill vertices and indices from cmd, also convert vertices to world coordinates fillVerticesAndIndices(cmd); // in the same batch ? if (batchable && (prevMaterialID == currentMaterialID || firstCommand)) { CC_ASSERT(firstCommand || _triBatchesToDraw[batchesTotal].cmd->getMaterialID() == cmd->getMaterialID() && "argh... error in logic"); _triBatchesToDraw[batchesTotal].indicesToDraw = cmd->getIndexCount(); _triBatchesToDraw[batchesTotal].cmd = cmd; } else { // is this the first one? if (!firstCommand) { batchesTotal ; _triBatchesToDraw[batchesTotal].offset = _triBatchesToDraw[batchesTotal-1].offset _triBatchesToDraw[batchesTotal-1].indicesToDraw; } _triBatchesToDraw[batchesTotal].cmd = cmd; _triBatchesToDraw[batchesTotal].indicesToDraw = (int) cmd->getIndexCount(); // is this a single batch ? Prevent creating a batch group then if (!batchable) currentMaterialID = -1; } // capacity full ? if (batchesTotal 1 >= _triBatchesToDrawCapacity) { _triBatchesToDrawCapacity *= 1.4; _triBatchesToDraw = (TriBatchToDraw*) realloc(_triBatchesToDraw, sizeof(_triBatchesToDraw[0]) * _triBatchesToDrawCapacity); } prevMaterialID = currentMaterialID; firstCommand = false; } batchesTotal ; /************** 2: Copy vertices/indices to GL objects *************/ // false if (conf->supportsShareableVAO() && conf->supportsMapBuffer()) { //Bind VAO GL::bindVAO(_buffersVAO); //Set VBO data glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]); // option 1: subdata // glBufferSubData(GL_ARRAY_BUFFER, sizeof(_quads[0])*start, sizeof(_quads[0]) * n , &_quads[start] ); // option 2: data // glBufferData(GL_ARRAY_BUFFER, sizeof(_verts[0]) * _filledVertex, _verts, GL_STATIC_DRAW); // option 3: orphaning glMapBuffer // FIXME: in order to work as fast as possible, it must "and the exact same size and usage hints it had before." // source: https://www.opengl.org/wiki/Buffer_Object_Streaming#Explicit_multiple_buffering // so most probably we won t have any benefit of using it glBufferData(GL_ARRAY_BUFFER, sizeof(_verts[0]) * _filledVertex, nullptr, GL_STATIC_DRAW); void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); memcpy(buf, _verts, sizeof(_verts[0]) * _filledVertex); glUnmapBuffer(GL_ARRAY_BUFFER); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(_indices[0]) * _filledIndex, _indices, GL_STATIC_DRAW); } else { // Client Side Arrays #define kQuadSize sizeof(_verts[0]) glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(_verts[0]) * _filledVertex , _verts, GL_DYNAMIC_DRAW); GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); // vertices glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, vertices)); // colors glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, colors)); // tex coords glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, texCoords)); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(_indices[0]) * _filledIndex, _indices, GL_STATIC_DRAW); } /************** 3: Draw *************/ for (int i=0; i<batchesTotal; i) { CC_ASSERT(_triBatchesToDraw[i].cmd && "Invalid batch"); _triBatchesToDraw[i].cmd->useMaterial(); glDrawElements(GL_TRIANGLES, (GLsizei) _triBatchesToDraw[i].indicesToDraw, GL_UNSIGNED_SHORT, (GLvoid*) (_triBatchesToDraw[i].offset*sizeof(_indices[0])) ); _drawnBatches ; _drawnVertices = _triBatchesToDraw[i].indicesToDraw; } /************** 4: Cleanup *************/ if (Configuration::getInstance()->supportsShareableVAO()) { //Unbind VAO GL::bindVAO(0); } else { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } _queuedTriangleCommands.clear(); _filledVertex = 0; _filledIndex = 0; } void TrianglesCommand::useMaterial() const { //Set texture GL::bindTexture2D(_textureID); if (_alphaTextureID > 0) { // ANDROID ETC1 ALPHA supports. GL::bindTexture2DN(1, _alphaTextureID); } //set blend mode GL::blendFunc(_blendType.src, _blendType.dst); _glProgramState->apply(_mv); } void GLProgramState::apply(const Mat4& modelView) { applyGLProgram(modelView); applyAttributes(); applyUniforms(); } void GLProgramState::applyGLProgram(const Mat4& modelView) { CCASSERT(_glprogram, "invalid glprogram"); updateUniformsAndAttributes(); // set shader _glprogram->use(); _glprogram->setUniformsForBuiltins(modelView); }

缺陷: 1)每次render都会重新更新VBO中的vertex data,可能这样比较适合 2)glVertexAttribPointer和GLProgramState分离,GLProgramState并不起作用


相关推荐:


苏州JAVA培训   苏州JAVA培训班   苏州JAVA培训机构

倒计时
11: 59: 19
课程热线:13013833891 | 客服时间:9:00-22:00(其他时间请在线预约报名或留言)
机构介绍
其然软件是一所专业从事程序编程语言开发培训的机构,我们开设有JAVA、.NET、C/C++,WEB前端等课程,其中JAVA为其然软件的核心课程,从2011年至今已为江浙沪培养一批又一批的专业型软件技术开发人才,每一期学员的就业l都在80%以上,我们有科学的课程体系,人性化的学习管理,努力为昆山地区的软件事业贡献出自己的一份力量。 做朴实的软件开发培训是其然软件的宗旨,朴素而...【详情】
相关课程
其他城市
相关机构

申请试听名额

已有10254人申请免费试听

01电话咨询 | 13013833891

QQ:1413838287
加盟合作:0755-83654572