gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-28 12:41:09 26 4
gpt4 key购买 nike

我一直在尝试获取 GLCameraRipple来自 Apple 在 swift 项目中运行的示例。不幸的是,这在很大程度上依赖于使用仅在 Objective-C 中可用的 C 风格线程安全数组。

我一直在尝试使用桥接头,以便模拟可以在 Objective-C 代码中运行,绘图可以在 swift 代码中运行。这样线程安全就不是问题了。

除了少数异常(exception),我已经将 Objective-C 代码几乎完全翻译成 swift。我确实剔除了一些额外的数学运算,因为纹理与我需要的屏幕大小相同。如果您想查看我的翻译,我已将它们放在下面。

无论如何,我已经制作了一个类,可以在具有 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?

Simulation.swift

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 (from apple)

最佳答案

Are you allowed to pass in data from an objective-c code to a glBuffer?

为什么不允许你? Swift 有一个指针 API(UnsafePointer<T>UnsafeMutablePointer<T> 等)正是为了这个目的。显然这是“不安全的”,因为 [Objective-]C 指针指向的底层内存可能会在 Swift 指针不知道的情况下随时更改。它也没有关于它指向的内存块大小的信息。

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

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

关于ios - 是否允许指向 Objective-C 数组的指针(通过桥接 header )?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39340665/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com