繁体   English   中英

是否允许指向Objective-C数组的指针(通过桥接标头)?

[英]Are pointers to Objective-C arrays (via a bridging header) allowed?

我一直试图从一个快速项目中运行的Apple获得GLCameraRipple示例。 不幸的是,这在很大程度上依赖于使用C型,仅在Objective-C中可用的线程安全数组。

我一直在尝试使用桥接标头,以便模拟可以在Objective-C代码中运行,而图形可以在快速代码中运行。 这样,线程安全的事情就不会成为问题。

我已经使用了Objective-C代码,几乎将它翻译成很快的代码,但有一些例外。 我确实剔除了一些额外的数学运算,因为纹理与屏幕的尺寸相同,可以满足我的需求。 如果您想查看我的翻译,请把它们放在下面。

无论如何,我已经创建了一个类,它将在带有opengl环境的任何xcode项目中运行。

import Foundation
import GLKit
import OpenGLES

class WaterDrawer
{
    static var sim = RippleModel()
    static var shade = Shader("Shader2")

    static func pt(pt: CGPoint)
    {
        sim.initiateRippleAtLocation(pt)
    }
    static func firstStart(width: Int, height: Int)
    {
        sim.initWithScreenWidth(width / 4, iheight: height / 4, accWidth: width, accHeight: height)
        shade.begin()
        buildMatrix(width, height: height)
        bufferSetup()
    }

    static func draw()
    {
        glUseProgram(shade.progId)


        let posLoc = GLuint(glGetAttribLocation(shade.progId, "pos"))
        let texLoc = GLuint(glGetAttribLocation(shade.progId, "tc"))


        glBindBuffer(GLenum(GL_ARRAY_BUFFER), texVBO);
        glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(sim.getVertexSize()), sim.getTexCoords(), GLenum(GL_DYNAMIC_DRAW));
        glVertexAttribPointer(texLoc, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))
        glEnableVertexAttribArray(texLoc)

        glBindBuffer(GLenum(GL_ARRAY_BUFFER), posVBO)
        glVertexAttribPointer(posLoc, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))
        glEnableVertexAttribArray(posLoc)


        let uniOrtho = glGetUniformLocation(shade.progId, "matrix")
        glUniformMatrix4fv(uniOrtho, 1, GLboolean(GL_FALSE), &orthographicMatrix)


        glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indVBO)


        glDrawElements(GLenum(GL_TRIANGLE_STRIP), GLsizei(sim.getIndexCount()), GLenum(GL_UNSIGNED_SHORT), nil)

        glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)
        glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), 0)
        glDisableVertexAttribArray(posLoc)
        glDisableVertexAttribArray(texLoc)
    }

    static func update()
    {
        sim.runSimulation()
    }


    static var posVBO:GLuint = 0
    static var texVBO:GLuint = 0
    static var indVBO:GLuint = 0
    static func bufferSetup()
    {
        Whirl.crashLog("Started passing in buffer data")

        glGenBuffers(1, &indVBO);
        glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indVBO);
        glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), GLsizeiptr(sim.getIndexSize()), sim.getIndices(), GLenum(GL_STATIC_DRAW));

        glGenBuffers(1, &posVBO);
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), posVBO);
        glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(sim.getVertexSize()), sim.getVertices(), GLenum(GL_STATIC_DRAW));


        glGenBuffers(1, &texVBO);
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), texVBO);
        glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(sim.getVertexSize()), sim.getTexCoords(), GLenum(GL_DYNAMIC_DRAW));

        Whirl.crashLog("Finished passing in buffer Data")
    }


    static var orthographicMatrix:[GLfloat] = []
    static func buildMatrix(width: Int, height: Int)
    {
        orthographicMatrix = glkitmatrixtoarray(GLKMatrix4MakeOrtho(0, GLfloat(width), 0, GLfloat(height), -100, 100))
        //Storage.upScaleFactor
    }
    static func glkitmatrixtoarray(mat: GLKMatrix4) -> [GLfloat]
    {
        var buildme:[GLfloat] = []
        buildme.append(mat.m.0)
        buildme.append(mat.m.1)
        buildme.append(mat.m.2)
        buildme.append(mat.m.3)
        buildme.append(mat.m.4)
        buildme.append(mat.m.5)
        buildme.append(mat.m.6)
        buildme.append(mat.m.7)
        buildme.append(mat.m.8)
        buildme.append(mat.m.9)
        buildme.append(mat.m.10)
        buildme.append(mat.m.11)
        buildme.append(mat.m.12)
        buildme.append(mat.m.13)
        buildme.append(mat.m.14)
        buildme.append(mat.m.15)
        return buildme

    }

}

因此,从理论上讲,此代码可以使用swift实现或Objective-C实现,我只需要切换启动网格的方式即可。

麻烦的是,当我使用Objective-C时,屏幕是空白的,我已经检查过了,缓冲区数据在帧捕获中看起来真的很奇怪。

是否允许将数据从Objective-C代码传递给glBuffer?

仿真快速

import Foundation
import GLKit
import OpenGLES


class RippleModel
{
    var screenWidth:UInt32 = 0
    var screenHeight:UInt32 = 0
    var poolWidth:UInt32 = 0
    var poolHeight:UInt32 = 0
    var screenWidthi:Int = 0
    var screenHeighti:Int = 0
    var poolWidthi:Int = 0
    var poolHeighti:Int = 0

    let touchRadius:Int = 5 //5 i think

    var rippleVertices:[GLfloat] = []
    var rippleTexCoords:[GLfloat] = []
    var rippleIndices:[GLushort] = []//NOTE IF CHANGE THIS TO INTO SO MUCH DRAW CALL

    var rippleSource:[GLfloat] = []
    var rippleDest:[GLfloat] = []

    var rippleCoeff:[GLfloat] = []


    var VertexSize:GLsizeiptr = 0
    var IndicieSize:GLsizeiptr = 0
    var IndicieCount:Int = 0

    func calculateSizes()
    {
        VertexSize = rippleVertices.count * sizeof(GLfloat)
        IndicieSize = rippleIndices.count * sizeof(GLushort)
        IndicieCount = rippleIndices.count

        Whirl.crashLog("Data sizes Vertex size \(VertexSize)\tIndicie Size \(IndicieSize) \tIndicie Count \(IndicieCount)")
    }
    func figureOutCoefficent()
    {
        for y in 0...(2 * touchRadius)
        {
            for x in 0...(2 * touchRadius)
            {
                let dx = x - touchRadius
                let dy = y - touchRadius
                let distance = sqrt(GLfloat(dx * dx + dy * dy))

                let me = y * (touchRadius*2 + 1) + x
                if (distance <= GLfloat(touchRadius))
                {
                    let factor = distance / GLfloat(touchRadius)
                    rippleCoeff[me] = -(cos(factor*GLfloat(M_PI))+1.0) * 256.0;
                }
                else
                {
                    rippleCoeff[me] = 0.0
                }
            }
        }

    }
    init()
    {

    }
    func initWithScreenWidth( iwidth: Int,  iheight: Int, accWidth: Int, accHeight: Int)
    {
        screenWidth = UInt32(accWidth);screenWidthi = Int(screenWidth)
        screenHeight = UInt32(accHeight);screenHeighti = Int(screenHeight)

        poolWidth = UInt32(iwidth);poolWidthi = Int(poolWidth)
        poolHeight = UInt32(iheight);poolHeighti = Int(poolHeight)


        //WE DONT NEED TEX COORD MUMBO JUMBO IT IS FULL SCREEN ALREADY
        Whirl.crashLog("Started allocation")

        rippleCoeff = [GLfloat](count: Int( (touchRadius * 2 + 1) * (touchRadius*2 + 1) ), repeatedValue: 0)
        figureOutCoefficent()

        let simCount:Int = Int(poolWidth + 2) * Int(poolHeight + 2)
        rippleSource = [GLfloat](count: simCount, repeatedValue: 0)
        rippleDest = [GLfloat](count: simCount, repeatedValue: 0)

        let locb:Int = Int(poolWidth * poolHeight * 2)
        rippleVertices = [GLfloat](count: locb, repeatedValue: 0)
        rippleTexCoords = [GLfloat](count: locb, repeatedValue: 0)

        rippleIndices = [GLushort](count: Int(poolHeight - 1) * Int((poolWidth * 2) + 2), repeatedValue: 0)

        Whirl.crashLog("Finished allocation")

        initMesh()

        calculateSizes()
    }
    func initMesh()
    {
        Whirl.crashLog("Started initting pos coords")

        for i in 0..<poolHeight
        {let ii = GLfloat(i)
            for j in 0..<poolWidth
            {let jj = GLfloat(j)
                let cordb:Int = Int(i*poolWidth+j)*2


                rippleVertices[cordb + 0] = (jj / GLfloat(poolWidth - 1)) * GLfloat(screenWidth)
                rippleVertices[cordb + 1] = (ii / GLfloat(poolHeight - 1)) * GLfloat(screenHeight)


                rippleTexCoords[cordb + 0] = ii / GLfloat(poolHeight - 1)
                rippleTexCoords[cordb + 1] = (jj/GLfloat(poolWidth - 1))

            }
        }

        Whirl.crashLog("Finished initting pos coords")

        Whirl.crashLog("Started initting index coords")

        var index = 0
        for i in 0 ..< poolHeighti-1
        {
            for j in 0 ..< poolWidthi
            {
                if (i%2 == 0)
                {
                    // emit extra index to create degenerate triangle
                    if (j == 0)
                    {
                        rippleIndices[index] = GLushort(i*poolWidthi+j);
                        index += 1;
                    }

                    rippleIndices[index] = GLushort(i*poolWidthi+j);
                    index += 1;
                    rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
                    index += 1;

                    // emit extra index to create degenerate triangle
                    if (j == (poolWidthi-1))
                    {
                        rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
                        index += 1;
                    }
                }
                else
                {
                    // emit extra index to create degenerate triangle
                    if (j == 0)
                    {
                        rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
                        index += 1;
                    }

                    rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
                    index += 1;
                    rippleIndices[index] = GLushort(i * poolWidthi + j);
                    index += 1;

                    // emit extra index to create degenerate triangle
                    if (j == (poolWidthi-1))
                    {
                        rippleIndices[index] = GLushort(i * poolWidthi + j);
                        index += 1;
                    }
                }
            }
        }


        Whirl.crashLog("Finished initting coords")
    }

    var firstUpdate = true
    func runSimulation()
    {
        if (firstUpdate)
        {firstUpdate = false; Whirl.crashLog("First update")}

        let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

        //dispatch_apply(Int(poolHeight), queue, {(y: size_t) -> Void in
        for y in 0..<poolHeighti {
            let pw = self.poolWidthi
            for x in 1..<(pw - 1)
            {
                let ai:Int = (y    ) * (pw + 2) + x + 1
                let bi:Int = (y + 2) * (pw + 2) + x + 1
                let ci:Int = (y + 1) * (pw + 2) + x
                let di:Int = (y + 1) * (pw + 2) + x + 2
                let me:Int = (y + 1) * (pw + 2) + x + 1

                let a = self.rippleSource[ai]
                let b = self.rippleSource[bi]
                let c = self.rippleSource[ci]
                let d = self.rippleSource[di]

                var result = (a + b + c + d) / 2.0 - self.rippleDest[me]
                result -= result / 32.0

                self.rippleDest[me] = result
            }
        }
        //)


        let hm1 = GLfloat(poolHeight - 1)
        let wm1 = GLfloat(poolWidth - 1)
        //dispatch_apply(poolHeighti, queue, {(y: size_t) -> Void in
        for y in 0..<poolHeighti{
            let yy = GLfloat(y)
            let pw = self.poolWidthi
            for x in 1..<(pw - 1)
            {let xx = GLfloat(x)
                let ai:Int = (y    ) * (pw + 2) + x + 1
                let bi:Int = (y + 2) * (pw + 2) + x + 1
                let ci:Int = (y + 1) * (pw + 2) + x
                let di:Int = (y + 1) * (pw + 2) + x + 2

                let a = self.rippleDest[ai]
                let b = self.rippleDest[bi]
                let c = self.rippleDest[ci]
                let d = self.rippleDest[di]

                var s_offset = ((b - a) / 2048)
                var t_offset = ((c - d) / 2048)

                s_offset = (s_offset < -0.5) ? -0.5 : s_offset;
                t_offset = (t_offset < -0.5) ? -0.5 : t_offset;
                s_offset = (s_offset >  0.5) ?  0.5 : s_offset;
                t_offset = (t_offset >  0.5) ?  0.5 : t_offset;

                let s_tc = yy / hm1
                let t_tc = xx / wm1

                let me = (y * pw + x) * 2
                self.rippleTexCoords[me + 0] = s_tc + s_offset
                self.rippleTexCoords[me + 1] = t_tc + t_offset

            }
        }
        //)

        let pTmp = rippleDest
        rippleDest = rippleSource
        rippleSource = pTmp
    }

    var firstRipple:Bool = true
    func initiateRippleAtLocation(location: CGPoint)
    {
        if (firstRipple)
        {firstRipple = false; Whirl.crashLog("First ripple placement")}

        let xIndex = Int((GLfloat(location.x) / GLfloat(screenWidth)) * GLfloat(poolWidthi))
        let yIndex = Int((1.0 - (GLfloat(location.y) / GLfloat(screenHeighti))) * GLfloat(poolHeight))

        let lowy = yIndex - touchRadius
        let highy = yIndex + touchRadius
        let lowx = xIndex - touchRadius
        let highx = xIndex + touchRadius


        //Whirl.crashLog("Ripple at (\(xIndex) , \(yIndex))\tX:(\(lowx) - \(highx))\tY:(\(lowy) - \(highy))")

        for y in lowy...highy
        {
            for x in lowx...highx
            {
                if (x > 0 && x < (poolWidthi - 1) && y > 0 && y < poolHeighti)
                {
                    let ind = (poolWidthi + 2) * (y + 1) + x + 1
                    let coef = (y-(yIndex-touchRadius))*(touchRadius*2+1)+x-(xIndex-touchRadius)
                    let past = rippleSource[ind]
                    let coe = rippleCoeff[coef]
                    if (coe < past)
                    {
                        rippleSource[ind] = coe
                    }

                }
            }
        }
    }

    func rippleLine(location1: CGPoint, location2: CGPoint)
    {
        if (firstRipple)
        {firstRipple = false; Whirl.crashLog("First ripple placement")}

        let xIndex1 = Int((GLfloat(location1.x) / GLfloat(screenWidth)) * GLfloat(poolWidthi))
        let yIndex1 = Int((1.0 - (GLfloat(location1.y) / GLfloat(screenHeighti))) * GLfloat(poolHeight))
        let xIndex2 = Int((GLfloat(location2.x) / GLfloat(screenWidth)) * GLfloat(poolWidthi))
        let yIndex2 = Int((1.0 - (GLfloat(location2.y) / GLfloat(screenHeighti))) * GLfloat(poolHeight))

        let lowy1 = yIndex1 - touchRadius
        let highy1 = yIndex1 + touchRadius
        let lowx1 = xIndex1 - touchRadius
        let highx1 = xIndex1 + touchRadius

        let lowy2 = yIndex2 - touchRadius
        let highy2 = yIndex2 + touchRadius
        let lowx2 = xIndex2 - touchRadius
        let highx2 = xIndex2 + touchRadius

        let lowx = min(lowx1, lowx2)
        let highx = max(highx1, highx2)
        let lowy = min(lowy1, lowy2)
        let highy = max(highy1, highy2)

        for y in lowy...highy
        {
            for x in lowx...highx
            {
                if (x > 0 && x < (poolWidthi - 1) && y > 0 && y < poolHeighti)
                {
                    let ind = (poolWidthi + 2) * (y + 1) + x + 1

                    let tar = ldist(CGPoint(x: xIndex1, y: yIndex1), p2: CGPoint(x: xIndex2, y: yIndex2), me: CGPoint(x: x, y: y))

                    let dx = x - Int(tar.x)
                    let dy = y - Int(tar.y)
                    let distq = (dx * dx + dy * dy)

                    if (distq < touchRadius * touchRadius)
                    {
                        let factor = sqrt(GLfloat(distq)) / GLfloat(touchRadius)

                        rippleSource[ind] = -(cos(factor*GLfloat(M_PI))+1.0) * 256.0;
                    }
                    //rippleSource[ind] = 1000
                }
            }
        }
    }

    func ldist(p1: CGPoint, p2: CGPoint, me: CGPoint) -> CGPoint
    {
        let diffX = p2.x - p1.x
        let diffY = p2.y - p1.y

        var target = CGPoint()
        if ((diffX == 0) && (diffY == 0))
        {
            target = p1
        }

        let t = ((me.x - p1.x) * diffX + (me.y - p1.y) * diffY) / (diffX * diffX + diffY * diffY)

        if (t < 0)
        {
            target = p1
        }
        else if (t > 1)
        {
            target = p2
        }
        else
        {
            target = CGPoint(x: (p1.x + t * diffX), y: (p1.y + t * diffY))
        }

        let int = CGPoint(x: round(target.x), y: round(target.y))
        return int
    }

    func getVertices() -> [GLfloat]
    {
        //Return the mesh positions
        return rippleVertices
    }
    func getTexCoords() -> [GLfloat]
    {
        //Return the array of texture coords
        return rippleTexCoords
    }
    func getIndices() -> [GLushort]
    {
        //Return the array of indices
        return rippleIndices
    }
    func getVertexSize() -> GLsizeiptr
    {
        //Return the size of the mesh position array
        return VertexSize
    }
    func getIndexSize() -> GLsizeiptr
    {
        //Return the byte size of the incicie array
        return IndicieSize
    }
    func getIndexCount() -> GLsizeiptr
    {
        //This goes in the draw call, count of indices
        return IndicieCount
    }
}

RippleModel.m(来自苹果)

由于OpenGL ES是纯C函数集,因此我认为传递快速数据类型的指针并不容易。

以下代码将提示您如何传递索引缓冲区。

var Indices: [GLubyte] = [
    0, 1, 2,
    2, 3, 0
]

var indexBuffer: GLuint = GLuint()
glGenBuffers(1, &indexBuffer)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indexBuffer)
glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), Indices.size(), Indices, GLenum(GL_STATIC_DRAW))

参考:这是带有工作代码的链接。 https://github.com/bradley/iOSSwiftOpenGL/blob/master/iOSSwiftOpenGL/OpenGLView.swift

是否允许将数据从Objective-C代码传递给glBuffer?

你为什么不被允许? Swift UnsafePointer<T>具有一个指针API( UnsafePointer<T>UnsafeMutablePointer<T>等)。 从[Objective-] C指针指向的基础内存可能随时更改而无需Swift指针知道的意义上,这显然是“不安全的”。 它还没有有关它指向的内存块大小的信息。

任何C指针或数组都可以桥接到Swift(可能是UnsafeMutablePointer<Void> ,您需要将其UnsafeMutablePointer<Void>转换为OpenGL类型)。

您可以通过取消引用指针(如果非零),并将指针处存储的值复制到Swift应用程序中的变量,来避免引用无效内存的任何风险。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM