Tutorial 1 - Create a window(创建窗口)

本文介绍如何利用GLUT库简化OpenGL编程中的窗口管理和事件处理等复杂任务,并通过实例演示了初始化GLUT、配置显示模式、创建窗口及设置渲染回调等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Background

The OpenGL spec does not specify any API in order to createand manipulate windows. Modern windowing systems that support OpenGLinclude a sub-system that provides the binding between an OpenGLcontext and the windowing system. In the X Window system that interfaceis called GLX. Microsoft provides WGL (pronounced: Wiggle) for Windowsand MacOS has CGL. Working directly with these interfaces in order tocreate a window in which to display graphics is usually grunt workwhich is why we use a high level library that abstracts away the finedetails. The library we use here is called the 'OpenGL utilitylibrary', or GLUT. It provides a simplified API for window managementas well as event handling, IO control and a few other services. Inaddition, GLUT is cross platform which makes portability easier.Alternatives to GLUT include SDL and GLFW.

Source walkthru

glutInit(&argc, argv);

This call initializes GLUT. The parameters can be provideddirectly from the command line and include useful options such as'-sync' and '-gldebug' which disable the asynchronous nature of X andautomatically checks for GL errors and displays them (respectively).

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

Here we configure some GLUT options. GLUT_DOUBLE enables doublebuffering (drawing to a background buffer while another buffer isdisplayed) and the color buffer where most rendering ends up (i.e. thescreen). We will usually want these two as well as other options whichwe will see later.

glutInitWindowSize(1024, 768);
glutInitWindowPosition(100, 100);
glutCreateWindow("Tutorial 01");

These calls specify the window parameters and create it. You also havethe option to specify the window title.

glutDisplayFunc(RenderSceneCB);

Since we are working in a windowing system most of the interaction withthe running program occurs via event callback functions. GLUT takescare of interacting with the underlying windowing system and providesus with a few callback options. Here we use just one - a "main"callback to do all the rendering of one frame. This function iscontinuously called by GLUT internal loop.

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

This is our first encounter with the concept of state in OpenGL. Theidea behind state is that rendering is such a complex task that itcannot be treated as a function call that receives a few parameters(and correctly designed functions never receive a lot of parameters).You need to specify shaders, buffers and various flags that effect howrendering will take place. In addition, you would often want to keepthe same piece of configuration across several rendering operations(e.g. if you never disable the depth test then there is no point inspecifying it for every render call). That is why most of theconfiguration of rendering operations is done by setting flags andvalues in the OpenGL state machine and the rendering calls themselvesare usually limited to the few parameters that revolve around thenumber of vertices to draw and their starting offset. After calling astate changing function that particular configuration remains intactuntil the next call to the same function with a different value. Thecall above sets the color that will be used when clearing theframebuffer (described later). The color has four channels (RGBA) andit is specified as a normalized value between 0.0 and 1.0.

glutMainLoop();

This call passes control to GLUT which now begins its own internalloop. In this loop it listens to events from the windowing system andpasses them via the callbacks that we configured. In our case GLUT willonly call the function we registered as a display callback(RenderSceneCB) to give us a chace to render the frame.

glClear(GL_COLOR_BUFFER_BIT);
glutSwapBuffers();

The only thing we do in our render function is to clear the framebuffer(using the color specified above - try changing it). The second calltells GLUT to swap the roles of the backbuffer and the frontbuffer. Inthe next round through the render callback we will render into thecurrent frames front buffer and the current backbuffer will bedisplayed.

<think>我们正在处理一个SQL错误[40000],具体是关于在非WindowAgg计划节点中使用了窗口函数(WindowFunc)。这个错误通常发生在执行计划生成阶段,当优化器或执行引擎发现窗口函数被放置在非窗口聚合节点中时。根据数据库内部原理,窗口函数需要特定的执行节点(如WindowAgg节点)来处理。如果在查询计划中,窗口函数没有被正确的执行节点包裹,就会抛出此类错误。可能的原因和解决方案:1.**查询语法错误**:检查窗口函数的使用是否符合SQL标准。窗口函数必须与OVER子句一起使用,且OVER子句需要定义窗口(如PARTITIONBY,ORDERBY等)。示例:`SELECTid,ROW_NUMBER()OVER(PARTITIONBYdeptORDERBYsalaryDESC)FROMemployees;`2.**数据库版本兼容性问题**:某些数据库版本可能对窗口函数的支持有特定要求或存在已知的Bug。请检查数据库的版本,并查阅官方文档是否有相关说明。如果可能,升级到最新版本或应用补丁。3.**复杂查询中的优化器错误**:有时,复杂的查询(尤其是包含子查询、连接和窗口函数的组合)可能会导致优化器生成错误的执行计划。可以尝试以下方法:-简化查询:将复杂查询拆分成多个步骤,使用临时表或公共表表达式(CTE)逐步处理。-使用提示(Hints):某些数据库支持查询提示来强制使用特定的执行计划,例如强制使用窗口聚合节点(如果支持)。-调整查询:重新组织查询逻辑,避免窗口函数嵌套在可能导致优化器混淆的位置。4.**窗口函数在非法上下文中使用**:例如,在WHERE子句或JOIN条件中直接使用窗口函数,这是不允许的,因为窗口函数的计算在逻辑上是在处理完WHERE、JOIN等子句之后。如果需要在条件中使用窗口函数的结果,应使用子查询或CTE。错误示例:`SELECT*FROMtableWHEREROW_NUMBER()OVER(ORDERBYcol)=1;`正确示例:`SELECT*FROM(SELECT*,ROW_NUMBER()OVER(ORDERBYcol)ASrnFROMtable)WHERErn=1;`5.**数据库特定的限制**:不同的数据库系统(如PostgreSQL,Oracle,SQLServer等)对窗口函数的实现可能有不同的限制。请参考具体数据库的文档。以下是一些常见数据库的参考链接:-PostgreSQL:[窗口函数](https://www.postgresql.org/docs/current/tutorial-window.html)[^1]-Oracle:[分析函数](https://docs.oracle.com/database/121/SQLRF/functions004.htm#SQLRF06174)[^2]-SQLServer:[窗口函数](https://docs.microsoft.com/en-us/sql/t-sql/queries/select-over-clause-transact-sql?view=sql-server-ver15)[^3]6.**权限问题**:虽然不太常见,但有时权限不足可能导致执行计划生成异常。检查用户是否有执行该查询的足够权限。如果你能提供具体的SQL查询和数据库类型,我们可以更精确地定位问题。§§相关问题§§1.如何调试复杂的SQL查询执行计划?2.窗口函数在哪些数据库中被支持?3.除了窗口函数,还有哪些方法可以实现类似的行级计算?</think> ### SQL错误[40000]:WindowFunc in non-WindowAgg plan node解决方案 该错误通常发生在窗口函数(如`ROW_NUMBER()`, `RANK()`, `LEAD()`等)被错误放置或误用时,特别是在以下场景: #### 📌 主要成因分析 1. **窗口函数非法嵌套** 在聚合函数内嵌窗口函数,例如: ```sql SELECT SUM(ROW_NUMBER() OVER (ORDER BY sales)) -- ✘ 非法嵌套 ``` 2. **WHERE/HAVING子句直接过滤** 直接在条件中引用窗口函数结果: ```sql WHERE ROW_NUMBER() OVER (PARTITION BY dept) = 1 --窗口函数不允许在WHERE中出现 ``` 3. **优化器计划节点冲突** 执行引擎将窗口函数错误分配到非窗口聚合节点处理(涉及查询优化器实现细节)[^1]。 #### ✅ 解决方案 **方案1:改用子查询/CTE包装窗口函数** ```sql SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn FROM employees ) AS subquery WHERE rn = 1; -- ✔ 正确使用 ``` **方案2:分步执行** ```sql -- 步骤1: 创建窗口函数的临时表 CREATE TEMP TABLE temp_employees AS SELECT *, RANK() OVER (PARTITION BY region ORDER BY sales DESC) AS sales_rank FROM sales_data; -- 步骤2: 基于临时表查询 SELECT * FROM temp_employees WHERE sales_rank <= 3; ``` **方案3:检查数据库兼容性** | 数据库 | 支持窗口函数的最低版本 | |---------------|------------------------| | PostgreSQL | 8.4+ | | MySQL | 8.0+ | | SQL Server | 2005+ | | Oracle | 8i+ | 若版本过低建议升级(如MySQL 5.x需升级到8.x)[^2]。 #### ⚠️ 注意要点 1. 确保`OVER()`子句完整定义分区和排序 2. 避免在聚合函数`GROUP BY`/`HAVING`中直接嵌入窗口函数 3. 检查索引:分区字段(如`dept`)建议建立索引 4. 大数据集考虑添加分页限制(如`LIMIT 1000`)避免计划节点选择错误 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值