|
|
March 14 Symbol Paths(转)
http://msdn2.microsoft.com/en-us/library/ms680689(VS.85).aspxThe library uses the symbol search path to locate debug symbols (.dbg file) for .dll, .exe, and .sys files by appending "\symbols" and "\dll" or "\exe" or "\sys" to the path. For example, the typical location of symbol files for .dll files is c:\mysymbols\symbols\dll. For .exe files, the location is c:\mysymbols\symbols\exe.
To specify where the symbol handler will search disk directories for symbol files, call the SymSetSearchPath function. Alternatively, you can specify a symbol search path in the UserSearchPath parameter of the SymInitialize function.
The UserSearchPath parameter in SymInitialize and the SearchPath parameter in SymSetSearchPath take a pointer to a null-terminated string that specifies a path, or series of paths separated by a semicolon. The symbol handler uses these paths to search for symbol files. If this parameter is specified as a non-null value, the symbol handler searches only the paths set by the application. If this parameter is NULL, the symbol handler first searches the current working directory of the application, then the system root directory (%windir%). If you set the _NT_SYMBOL_PATH or _NT_ALT_SYMBOL_PATH environment variable, the symbol handler searches for symbol files in the following order:
The current working directory of the application. The _NT_SYMBOL_PATH environment variable. The _NT_ALT_SYMBOL_PATH environment variable. To retrieve the search paths, call the SymGetSearchPath function.
The search path for program database (.pdb) files is different than the path for debug (.dbg) files. The algorithm is determined by the functionality of the symbol library. By default, Microsoft Visual C/C++ creates Microsoft format symbols, strips them from the image, and places them in a separate .pdb file. Typically, the .pdb file will be located in the directory that contains the executable image. Visual C/C++ embeds the absolute path to the .pdb file in the executable image. If the symbol handler cannot find the .pdb file in that location or if the .pdb file was moved to another directory, the symbol handler will locate the .pdb file using the search path described for .dbg files.
如何获取windows的调试符号文件 (转) http://blog.vckbase.com/zyq654321/archive/2004/11/01/1188.aspx
PDB(Program Database) file是一种最新的用于存贮debug信息的格式文件。
与它的两个“前辈”(COFF和CODEVIEW)不同的是,PDB可以保存所有种类的debug信息,并支持增量链接(incremental link)。此外,PDB文件是以单独文件的形式出现,而COFF和COEDEVIEW两种格式的debug信息是存在执行文件内的。(注:CODEVIEW格式的debug信息也可存于执行文件名,其后缀名为.dbg).
通常在调试时,我们无法获得一些系统DLL的调试符号,这样会让我们对程序运行的细节的了解可能会有一些问题,当然我们可以通过查看反汇编窗口来解决一些问题。但是如果你能够得到这个调试符号,是不是觉得会很爽。呵呵,爽是次要的,重要的是这些调试符号会强化你所需要的线索。要实现这一点,就须要有相应的windows调试符号文件,你可以通过下面的方法获得它:
symsrv*symsrv.dll*f:\localsymbols*http://msdl.microsoft.com/download/symbols
将此句加在项目属性中的[符号路径处](VC++.NET)即可。 其中f:\localsymbols是你的本地盘路径,请先确保它的存在。完成后,F5进行debug。第一次是时间比较长,这是因为在下载符号库文件。你可以在output窗口中看到一个接一个的符号库被加载……
提示,设定了此属性后可能会导致debug的速度下降。当然这是正常现象,东东多了么。
现在就去下它们吧,Enjoy!
另外也可以通过设定环境变量来实现:
环境变量法: Set _NT_SYMBOL_PATH = symsrv*symsrv.dll*f:\localsymbols*http://msdl.microsoft.com/download/symbols
具体设定位置:My Computer--->Properties---->Advanced--->Environment Varibles
不过偶建议最好用时再设它,不用时就不要设它,免得影响速度。
注: 关于获取SymSrv.dll ,请安装 Debugging Tools for Windows package January 28 由于spaces.live的博客用起来不方便也不美观
现已迁移到新的地址:
不过这里可能继续会发些零碎笔记 January 14 lua写文件(备忘):
function save(n) io.output("save"..n) serialize(contex) io.close() end
-- from the lua tutorials
function serialize (o) if type(o) == "number" then io.write(o) elseif type(o) == "string" then io.write(string.format("%q", o)) elseif type(o) == "table" then io.write("{\n") for k,v in pairs(o) do io.write(" [") serialize(k) io.write("] = ") serialize(v) io.write(",\n") end io.write("}\n") else error("cannot serialize a " .. type(o)) end end -------------------------------------------- 关键字: msn自动关闭
msn登录后自动关闭问题解决
我搜索了发现 这个目前网上还没正确答案!
先说说经历,可以直接跳到后面看解决办法!
一.经历:
前两天发现msn成功登录后, 鼠标移到上面就自动关闭了
不能进行任何操作,而微软的ie打开链接经常莫名奇秒地自动关闭
然后我用"世界之窗"(theworld.exe)一般没问题,就将就用了.
今天想用msn,却用不上,气了.
把以前那个反安装,然后重下个msn8.1安装后还是一样!
装了几个杀毒软件和木马工具
狂杀一遍,然后重起,不行!
看来得手动解决,首先用procexp.exe查看当前进程,没发现可疑的,
再用autoruns.exe查看启动项没有什么问题,查看它的服务项,好象
也没什么问题,除了几个我知道的软件外都标明软件公司的产品(一般的木马都不标微软的产品用来骗新手,
我初时也没在意,病毒其实就在里面).后面用360安全卫士查了一软件,并装上所有系统补丁(360会提示没装的系统补丁,我喜欢这个)
然后全面查找一遍,看看系统服务有个不打问题的ntmlsvc.exe上面标明是微软的产品...我好象没见过这个东西.于是点中它后点击修复选中
项,然后再上msn,晕还是不行,再刷新一遍那个ntmlsvc.exe怎么还在?这个修复选中项好象没用啊?
我于是到高级里的系统服务状态看看ntmlsvc.exe确实被启动的,右击它选停止,然后再查,没有了.
这时打开msn就可以正常上了!
二.解决办法:
其实很简单,用系统带的系统服务(在"开始-设置-控制面板-管理工具-服务"里),
查看到 ntmlsvc 服务,右击它把它停止就可以了.
或者用360safe.exe中的高级-系统状态-右击它停止也可以! January 03 fatal error C1900:
1>------ Build started: Project: sanguo, Configuration: Release Win32 ------ 1>Linking... 1>fatal error C1900: Il mismatch between 'P1' version '20060201' and 'P2' version '20050411' 1>LINK : fatal error LNK1257: code generation failed 1>Build log was saved at " file://e:\project\sanguo\temp\release\BuildLog.htm" 1>sanguo - 1 error(s), 0 warning(s) 上网查了一下估计是链接库打了补丁,而我的没打,造成vc编译版本不一致
to fan:
i can't email to you because your setting's limit.
fatal error C1900 generate because your compile tools's version different from the lib's(which someone compiled it using another vc2005).
solve this problem, only need patch the same sp1 or sp2 for your vc2005(i.e. your program and the lib complier's patch must same)!
December 20 1. GetKeyState(VK_CONTROL) & 0x80
2. GetAsyncKeyState(VK_LSHIFT) & 0x8000 3. BOOL GetKeyboardState(PBYTE lpKeyState); if(keystate[VK_RSHIFT]) { // +++ }
区别: 1:从windows消息队列中取得键盘消息,返回key status. 2:直接侦测键盘的硬件中断,返回key status. 3:当从windows消息队列中移除键盘消息时,才返回key status. 最近修改玩家反馈的bug(dmp文件)
有些内存错误很难查。
在一次无意中发现,在new中抛出异常的一种情况, 就是如果前面先new出一个内存,然后你对此内存越界修改(改到后面去了) 之后你再new新内存时就可能抛出异常; 例如你new char p[100]; 然后你修改 for( int =0; i<200); ++i){ p[i]=数据; } 完成后再new Mydata[10]; 就可能抛出异常!
以后crash发现new异常时可查看是否上述情况:)
参见:
3DSMAX_SDK_DavidLanier.pdf
(这些是以前跟踪分析的,其实挺简单,只是不懂时用来跟踪一遍就完全明白了, 写在这里是为了备忘)
先给一下lua的值定义:
lua中的值: TValue{ union{gc*,void*,int,bool}; //可回收对象,userlightdata, number, bool tt; //类别 }; 其中gc结构如下: GC{ gch; // gc head ts; // tstring u; // user data cl; // closure h; // table p; // proto uv; // upval th; // theard };
一。脚本给程序传表格
以下代码摘自boswars,用来分析: 脚本如下:
test( {Name = "sprite-mana", File = "general/mana2.png", Offset = {0, -1}, Size = {31, 4}} ) // {}中即是表格
程序如下
void test(lua_State *l) { lua_pushnil(l); while (lua_next(l, i + 1)) { key = LuaToString(l, -2); // key name if (!strcmp(key, "Name")) { name = LuaToString(l, -1); } else if (!strcmp(key, "File")) { File = LuaToString(l, -1); } else if (!strcmp(key, "Offset")) { if (!lua_istable(l, -1) || luaL_getn(l, -1) != 2) { LuaError(l, "incorrect argument"); } lua_rawgeti(l, -1, 1); // offsetX lua_rawgeti(l, -2, 2); // offsetY HotX = LuaToNumber(l, -2); HotY = LuaToNumber(l, -1); lua_pop(l, 2); // Pop offsetX and Y } else if (!strcmp(key, "Size")) { if (!lua_istable(l, -1) || luaL_getn(l, -1) != 2) { LuaError(l, "incorrect argument"); } lua_rawgeti(l, -1, 1); // Width lua_rawgeti(l, -2, 2); // Height Width = LuaToNumber(l, -2); Height = LuaToNumber(l, -1); lua_pop(l, 2); // Pop Width and Height } else { // Error. LuaError(l, "incorrect field '%s' for the DefineSprite." _C_ key); } lua_pop(l, 1); // pop the value; } }
lua调用我们的函数void test(lua_State *l)后变成: --- 表
我们需要先 lua_pushnil(l);(把nil作为key)后: --- nil --- 表
lua_next(l,1)后://1是表的位置,key则是上面的nil --- value // 得到的value --- key // 得到的key --- 表
lua_rawgeti(l, -1, 1); //offsetX; 参数-1是table(value是一个表), // 1是表的下标, 得到offsetX存在top,并inc top
--- offsetX --- value --- key --- 表
lua_rawgeti(l, -2, 1); //offsetY; 参数-2是table(value是一个表)(因为上面压入offsetX,所以变成-2了) // 1是表的下标, 得到offsetX存在top,并inc top --- offsetY --- offsetX --- value --- key --- 表
使用 HotX = LuaToNumber(l, -2);
HotY = LuaToNumber(l, -1); 保存得到的offsetX和offsetY
然后将它们出栈: lua_pop(l, 2); // Pop offsetX and offsetY 变成: --- value --- key --- 表
再将value出栈: lua_pop(l, 1); // pop the value; 变成: --- key --- 表
最后回到while函数继续调用 lua_next(l,1)://1是表的位置,key则是上面的key(上一次得到的key), //这样些函数数又将会得到下一个key和value放堆栈中 变成: --- 下一个value --- 下一个key --- 表
如此循环!
附:
这里有一篇类似文章参见:
使用lua_next()遍历表
二。程序生成表格给脚本:
以下代码也是从boswar拷过来的,挺简单就不分析了
static int CclFilteredListDirectory(lua_State *l, int type, int mask) { char directory[256]; const char *userdir; std::vector<FileList> flp; int n; int i; int j; int pathtype;
LuaCheckArgs(l, 1); userdir = lua_tostring(l, 1); n = strlen(userdir);
pathtype = 0; // path relative to stratagus dir if (n > 0 && *userdir == '~') { // path relative to user preferences directory pathtype = 1; }
// security: disallow all special characters if (strpbrk(userdir, ":*?\"<>|") != 0 || strstr(userdir, "..") != 0) { LuaError(l, "Forbidden directory"); }
if (pathtype == 1) { ++userdir; sprintf(directory, "%s/%s", UserDirectory.c_str(), userdir); } else { sprintf(directory, "%s/%s", StratagusLibPath.c_str(), userdir); } lua_pop(l, 1);
lua_newtable(l); n = ReadDataDirectory(directory, NULL, flp); for (i = 0, j = 0; i < n; ++i) { if ((flp[i].type & mask) == type) { lua_pushnumber(l, j + 1); lua_pushstring(l, flp[i].name); lua_settable(l, 1); ++j; } delete[] flp[i].name; }
return 1; }
附:这个可参考:
Lua 语言和C集成调研小结
November 20 游戏中换装处理(备忘)
一.cha 结构: cha中可有几个model(对应为部位,可切换) 每个model可有几个mtl(即subset), 每个mtl可作为一个pass, 该mtl中可有几层贴图 但是由于硬件多层贴图的限制可考虑只充许2层, 否则可能需要多次pass
二.cha update: updatebone(计算当前骨骼运行时矩阵) -- 注意,骨骼的骨架数据及骨骼的动画数据可共享 updatemodel(计算模型中动画) -- 注意,模型的网格数据及模型的动画数据可共享
注意: 需要将每model中引用到的骨骼运行时矩阵(在updatebone中计算好了)拷贝到该model中, 以便在后面渲染每个模型时能用上. 优化: 人物不可见时可不更新动画,但要更新动作(即当前播放第几个动作的第几帧), 故上述两函数可再追加一个标志说明是更新动作还是动画
三.cha render: 遍历渲染每一个model: for(i loop models) { 1. 设置每个模型的vb和ib: (vb和ib是静态创建的) setstream(model's vb && ib) 2. 渲染每一个模型 a. 把model引用到的运行时矩阵乘上MVP设置给vs b. 分pass画: for(i loop mtls){ 把每个mtl设置给vs drawpass(i) } } 优化: 在第2部时要把model引用到的运行时矩阵乘上MVP设置给vs中的常量寄存器, 然后用每个顶点的矩阵索引及权重进行混合(矩阵索引需要vs1.1中的寻址寄存器a0.x)
另外,只有整体transform变换的模型(没有顶点或骨骼动画, 如地面上不同位置不同面向的不动的树)要与人物模型分开处理, 这类物件可用类似上述的常量矩阵数组的技术进行instancing批次渲染(带skin的instancing批次渲染由于常量寄存器已变骨骼矩阵使用, 因此一般需要硬件支持,如使用顶点纹理来保存骨骼矩阵,参见前面文章instancing批次渲染)
疑问: 目前有一个疑问,上述的渲染需不需要换成按贴图排序再渲染. 还有怎么在只支持vs1.1的显卡下实现skin instancing,或者有其它什么优化的方案?
November 19 instancing批次画:
具体实现参见dxsdk9.0c中的instancing_2005(未包括最后一种需要sm3.0支持的技术) 一.单个shade const: V( g_pEffect->Begin( &cPasses, 0 ) ); for( iPass = 0; iPass < cPasses; iPass++ ) { V( g_pEffect->BeginPass( iPass ) ); // Render the boxes with the applied technique V( g_pEffect->SetTexture( g_HandleTexture, g_pBoxTexture ) );
for( int nRemainingBoxes = 0; nRemainingBoxes < g_NumBoxes; nRemainingBoxes++ ) { // set the box instancing array V( g_pEffect->SetVector( g_HandleBoxInstance_Position, &g_vBoxInstance_Position[nRemainingBoxes] ) ); V( g_pEffect->SetVector( g_HandleBoxInstance_Color, (D3DXVECTOR4*)&g_vBoxInstance_Color[nRemainingBoxes] ) ); // The effect interface queues up the changes and performs them // with the CommitChanges call. You do not need to call CommitChanges if // you are not setting any parameters between the BeginPass and EndPass. V( g_pEffect->CommitChanges() ); V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 4 * 6, 0, 6 * 2 ) ); }
V( g_pEffect->EndPass() ); } V( g_pEffect->End() );
二.多个shade const(因为使用类似于矩阵板实现skin bone的方法,所以存在冲突不能同时使用在骨骼动画中) V( g_pEffect->Begin( &cPasses, 0 ) ); for( iPass = 0; iPass < cPasses; iPass++ ) { V( g_pEffect->BeginPass( iPass ) ); // Render the boxes with the applied technique V( g_pEffect->SetTexture( g_HandleTexture, g_pBoxTexture ) );
int nRemainingBoxes = g_NumBoxes; while( nRemainingBoxes > 0 ) { // determine how many instances are in this batch (up to g_nNumBatchInstance) int nRenderBoxes = min( nRemainingBoxes, g_nNumBatchInstance );
// set the box instancing array V( g_pEffect->SetVectorArray( g_HandleBoxInstance_Position, g_vBoxInstance_Position + g_NumBoxes - nRemainingBoxes, nRenderBoxes) ); V( g_pEffect->SetVectorArray( g_HandleBoxInstance_Color, (D3DXVECTOR4*)(g_vBoxInstance_Color + g_NumBoxes - nRemainingBoxes), nRenderBoxes) ); // The effect interface queues up the changes and performs them // with the CommitChanges call. You do not need to call CommitChanges if // you are not setting any parameters between the BeginPass and EndPass. V( g_pEffect->CommitChanges() ); V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, nRenderBoxes * 4 * 6, 0, nRenderBoxes * 6 * 2 ) );
// subtract the rendered boxes from the remaining boxes nRemainingBoxes -= nRenderBoxes; }
V( g_pEffect->EndPass() ); } V( g_pEffect->End() );
三. vs3.0 的hwinstance(需要多流INSTANCEDATA支持): 这种方法是GPU通过虚拟复制(virtually duplicating)把顶点从第一个流打包到第二个流中。(也就是硬件使用多流和自动打包的方式帮忙实际了类似上述第二种的instance批次画)
// Stream zero is our model, and its frequency is how we communicate the number of instances required, // which in this case is the total number of boxes V( pd3dDevice->SetStreamSource( 0, g_pVBBox, 0, sizeof(BOX_VERTEX)) ); V( pd3dDevice->SetStreamSourceFreq( 0, D3DSTREAMSOURCE_INDEXEDDATA | g_NumBoxes ) ); // Stream one is the instancing buffer, so this advances to the next value // after each box instance has been drawn, so the divider is 1. V( pd3dDevice->SetStreamSource( 1, g_pVBInstanceData, 0, sizeof( BOX_INSTANCEDATA_POS ) ) ); V( pd3dDevice->SetStreamSourceFreq( 1, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) );
V( pd3dDevice->SetIndices( g_pIBBox ) ); // Render the scene with this technique // as defined in the .fx file V( g_pEffect->SetTechnique( g_HandleTechnique ) ); V( g_pEffect->Begin( &cPasses, 0 ) ); for( iPass = 0; iPass < cPasses; iPass++ ) { V( g_pEffect->BeginPass( iPass ) ); // Render the boxes with the applied technique V( g_pEffect->SetTexture( g_HandleTexture, g_pBoxTexture ) ); // The effect interface queues up the changes and performs them // with the CommitChanges call. You do not need to call CommitChanges if // you are not setting any parameters between the BeginPass and EndPass. V( g_pEffect->CommitChanges() ); V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 4 * 6, 0, 6 * 2 ) ); V( g_pEffect->EndPass() ); } V( g_pEffect->End() ); V( pd3dDevice->SetStreamSourceFreq( 0, 1 ) ); V( pd3dDevice->SetStreamSourceFreq( 1, 1 ) );
四. 带骨骼实现的批次(顶点纹理方式):
上述方法不好同时实现skinning, 如果需要实现skinning,可以尝试把所有实体的所有骨骼信息储存为一张纹理,之后为相应的实体选择正确的骨骼,这需要用到Shader Model3.0中的顶点纹理访问功能。如果使用这种技术,那么访问顶点纹理带来的性能消耗是不确定的,应该实现进行测试。
具体例子也可以参考:
NoInstancing:
ShaderInstancing:
HardwareInstancing:
VFetchInstancing:
November 14 WOW的地形shader祥细解释
SPXG // 标识 // 用到5张图片: { blendTexture = 0 layer0Texture = 1 layer1Texture = 2 layer2Texture = 3 layer3Texture = 4 } !!ARBfp1.0
// 定义常量: PARAM c[1] = { { 1, 0.30000001, 0.69999999 } };
// 声明3个寄存器: TEMP R0; TEMP R1; TEMP R2;
// 开始混合: // 一.第0层和第1层使用第4张图的x通道作为alpha进行混合: TEX R1, fragment.texcoord[0], texture[0], 2D; TEX R0, fragment.texcoord[1], texture[1], 2D; ADD R2, R0, -R1; // r2=Tex1-Tex0
TEX R0, fragment.texcoord[4], texture[4], 2D; MAD R2, R0.x, R2, R1; // r2 = Tex4.x*r2+Tex0
// 说明: // 其中的Tex4.x是对应第1层alpha值, 下面把Tex4.x当a1看 // 即 r2 = a1 * (Tex1-Tex0) + Tex0 // 转换一下即是: Tex0*(1-a1)+a1*Tex1, 呵呵,看到了吧,这就是混合公式!
// 二.第2层和前面结果使用第4张图的y通道作为alpha进行混合: TEX R1, fragment.texcoord[2], texture[2], 2D; ADD R1, R1, -R2; // r1=Tex2-r2
MAD R2, R0.y, R1, R2; // r2 = Tex4.y*r1+r2, 即 a2*r1+r2 = a2*(Tex2-r2)+r2, 即r2*(1-a2)+Tex2*a2, 其中r2即是上次0和1层混合后的结果
// 三.第3层和前面结果使用第4张图的z通道作为alpha进行混合: TEX R1, fragment.texcoord[3], texture[3], 2D; ADD R1, R1, -R2; // r1=Tex3-r2
MAD R1, R0.z, R1, R2; // r1=a3*r1+r2 , 即 a3*r1+r2 = a3*(Tex3-r2)+r2, 即r2*(1-a3)+Tex3*a3 // 这样r1就保存了最终的混合结果
// 四.让阴影地表光泽系数为0(Tex4.w即a通道代表地形的阴影,0为阴影,1为正常.而每层贴图中的a通道是光泽通道,所以R1.w保存的是最终的光泽通道值): MUL R0.x, R1.w, R0.w; // r0.x = r1.w(光泽)*Tex4.w(阴影值, 是阴影则=0,否则=1)
// 计算削减系数? MAD R0.w, R0, c[0].y, c[0].z; // r0乘上0.3(削减了30%)再加上一个常量0.69999999
// 反射高光 = secondary_color(反射光)*光泽: MUL R0.xyz, R0.x, fragment.color.secondary;
// 贴图最终color = 最终贴图混出的color*削减系数: MUL R1.xyz, R1, R0.w;
// 贴图最终color * primary_color(光照色或是顶点色) + 反射高光: MAD result.color.xyz, R1, fragment.color.primary, R0;
// alpha: MOV result.color.w, c[0].x;
END 参考资料: <WOW的地形渲染>: http://dev.csdn.net/author/ZERO2046/1b8df53b7f034e7999d70e0cac5665f6.html魔兽世界的地形渲染,基本上有三种渲染路径:固定渲染管线(其中是不是又分几种就不清楚了);shader(带高光);shader(不带高光) 用到shader的渲染路径又分别针对1层,2层,3层,4层(最多允许每个chunk使用4层纹理)专门写了shader代码。 用MyWarCraftStudio打开WOW的misc.mpq包,shader \ pixel \ 目录下以"terrain"打头的bls文件就是地形渲染使用的shader,带有"_s"后缀的是带高光的渲染,否则就是不带高光的。 我仔细看了其中的terrain4_s.bls(用UltraEdit之类的工具可以直接当成文本文件打开)。是汇编形式的ps代码,由于之前俺只用过c形式的HLSL所以看起来有点吃力,好在还是看明白了。 texture0~3就是待混合的4层纹理,每层纹理的a通道是该层纹理对应的高光通道;texture4是一张用来控制混合权重的alpha纹理。texture4的r,g,b通道分别对应texture1~3的alpha值,而texture4.a则代表地形的阴影,0为阴影,1为正常。 混合的公式为res_n = res_n-1 * ( 1 - alpha_n ) + texture_n * alpha_n。其中n代表第n层纹理。res_n代表第n层混合后的结果。 从代码可以看出,最终混合结果的a通道(高光通道)被乘以阴影值,也就是说阴影中没有高光。同时,阴影中的diffuse光照被削减了30%。 1,2,3层纹理混合,以及不带高光的情况想必也没有什么特别之处,也不去细看了。 值得一提的是我原来一直以为WOW的地形渲染只用了ps_1_1,但从这个shader看用了5张纹理,超出了ps_1_1的4个纹理采样的限制,所以至少使用了ps_1_4(允许6个纹理采样)。而1~3层纹理混合的情况使用ps_1_1就够了。我不知道在渲染时频繁切换ps版本会不会收到性能上的惩罚,但有些显卡(比如NV的5200)同样的代码在ps_1_4上运行要比在ps_1_1上运行慢很多。 至于固定渲染管线的渲染路径,由于不可能看到代码,具体如何实现多层纹理混合无法揣测,集合了各层纹理混合系数的alpha图应该不能直接用于渲染,因为固定渲染管线似乎只能用a通道来控制混合系数,可能需要将这张纹理拆成4张才行。。。 地形pvs 将地形分成n*n个区域,分成32层 然后,遍历每个区域, 在每个区域上的每层上向其它区域拉一直接,测试它们之间是否有障碍(不用测试三角形只用比较经过的区域内每个格子高度),是则表示当前所在区域看不见所测区域,保存此PVS供用. 注意PVS要用bit来保存,否则很大
参见: GameDev.net -- Terrain Geomorphing in the Vertex Shader http://www.gamedev.net/columns/hardcore/geomorph/
geomorph可将格子进行4次lod, 并在不同lod的格子边界进行插入点形成新的三角形(以免出现T形裂缝) 由于lod形成的高度差,所以还可以设置一个error充许值.具体参见原文(该地形也实现了类似目前一些网游所用的alpha混合多层贴图)
地形碰撞计算: 一.如果是鼠标点击地面, 可将射线固定长度并分段,然后用射线与每一个分段上的点所落在的地面tile(两个三角形)进行求交, 相交则返回对应位置,否则继续与下一个段上的点所落在的地面tile求交 /* 0 1 ----> | \ | | \ | 2 V --- 3 */ 这里不讨论点击屏幕求射线方法与射线分段处理,只算求交 如下d3d求交得出uv,再求位置: VECTOR3 vPickPos; // 右边: if( D3DXIntersectTri(&v0, &v1, &v3, &vOrig, &vDir, &u, &v, NULL) == TRUE) { vPickPos = v0 + u * (v1 - v0) + v * (v3 - v0); return vPickPos.z; } // 左边: if( D3DXIntersectTri(&v0, &v3, &v2, &vOrig, &vDir, &u, &v, NULL) == TRUE) { vPickPos = v0 + u * (v3 - v0) + v * (v2 - v0); return vPickPos.z; }
二.如果是仅是求地表某点高度 则可用uv重心求法(注意上述第一点的d3d的那个uv重心求法不太一样,他的uv跟他的向量走?) float u = (fX-(int)fX); float v = (fY-(int)fY);
float p0 = fHeight[0]; float p1 = fHeight[1]; float p2 = fHeight[2]; float p3 = fHeight[3];
if(u>v){ // 右边 return p0 + u * (p1 - p0) + v * (p3 - p1);; } else{ // 左边 return p0 + u * (p3 - p2) + v * (p2 - p0); }
November 12 1. 最简单的一张带alpha的贴图直接uv动画 2. 另一种是使用序列贴图, 即水的动画贴图,可在每个自定义大小的格子播放相同的一帧图片来实现.
 3. 反射水面: 上述其中一种方法再加上带bump map效果的反射图
下面给出最后一种具体例子:
用d3d固定管道实现bump mapping振动/移动的水:
(注意:该例子只用D3DTOP_BUMPENVMAP没用D3DTOP_BUMPENVMAPLUMINANCE): // 混合状态: m_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); m_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); m_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
// 贴图基台0: // 贴图因子(见后面的alpha参数D3DTA_TFACTOR): m_pD3DDevice->SetRenderState(D3DRS_TEXTUREFACTOR, 0x90000000); // 设置Bump map: 就是一些uv偏移值,保存在bump贴图中(还可以保存一个附加的光照值) m_pD3DDevice->SetTexture(0, m_pTexBump); m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_BUMPENVMAP); m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTA_DIFFUSE);//D3DTOP_DISABLE); // bump矩阵(参见上面msdn链接说明): m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVMAT00, F2DW(0.05f)); m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVMAT01, F2DW(0.0f)); m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVMAT10, F2DW(0.0f)); m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVMAT11, F2DW(0.05f)); m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVLSCALE, F2DW(1.0f)); m_pD3DDevice->SetTextureStageState(0, D3DTSS_BUMPENVLOFFSET, F2DW(0.0f)); // uv矩阵(uv动画用): m_pD3DDevice->SetTransform(D3DTS_TEXTURE0, &m_MatTransEau); m_pD3DDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
// 贴图基台1: // 反射图(可实时计算): // Etage 1 : affichage de la texture de r閒lexion m_pD3DDevice->SetTexture(1, m_pEnvMiroir->GetMiroir()); // m_pD3DDevice->SetTextureStageState (1, D3DTSS_COLOROP, D3DTOP_SELECTARG1); m_pD3DDevice->SetTextureStageState (1, D3DTSS_COLORARG1, D3DTA_TEXTURE); m_pD3DDevice->SetTextureStageState (1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); m_pD3DDevice->SetTextureStageState (1, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); // uv矩阵(投影矩阵,将贴图映射到水面用): m_pD3DDevice->SetTransform(D3DTS_TEXTURE1, &m_pScene->GetCameraCourante()->GetMatriceProjectionTexture()); m_pD3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION); m_pD3DDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_PROJECTED |D3DTTFF_COUNT3); m_pD3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); m_pD3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
// set fvf, vb 和 ib: m_pD3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX); m_pD3DDevice->SetStreamSource(0, m_pVB, 0, sizeof(CUSTOMVERTEX)); m_pD3DDevice->SetIndices(m_pIB);
// draw: m_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, NB_VERTEX_EAU, 0, NB_TRIANGLE_EAU);
提示:
上述的bump矩阵只是简单的偏移,实际的uv动画使用了另一个贴图uv矩阵(每帧更新,使得uv移动)来设置的,
另外一个更好技巧是可以使用bump矩阵直接应用sin函数,这样会使用得水波有一定的振动,效果挺好:
D3DXMATRIX matBumpMat;
const static DWORD startick(GetTickCount()); DWORD dwtime=GetTickCount()-startick; float time=(float)dwtime/1000; FLOAT r = 0.005f; matBumpMat._11 = r*cosf(time*8.0f); matBumpMat._12 = r*sinf(time*8.0f); matBumpMat._21 = r*sinf(time*8.0f); matBumpMat._22 =-r*cosf(time*8.0f);
m_pD3DDevice->SetTextureStageState(0,D3DTSS_BUMPENVMAT00,F2DW(matBumpMat._11)); m_pD3DDevice->SetTextureStageState(0,D3DTSS_BUMPENVMAT01,F2DW(matBumpMat._12)); m_pD3DDevice->SetTextureStageState(0,D3DTSS_BUMPENVMAT10,F2DW(matBumpMat._21)); m_pD3DDevice->SetTextureStageState(0,D3DTSS_BUMPENVMAT11,F2DW(matBumpMat._22));
上述方法需要检测是否支持 D3DTEXOPCAPS_BUMPENVMAP
关于bump mapping参见msdn:
1. Bump Mapping (Direct3D 9) http://msdn2.microsoft.com/en-us/library/bb172379.aspx
2. Bump Mapping Formulas (Direct3D 9) http://msdn2.microsoft.com/en-us/library/bb172380.aspx
3. Bump Map Pixel Formats (Direct3D 9) http://msdn2.microsoft.com/en-us/library/bb172381.aspx
4.Using Bump Mapping (Direct3D 9) http://msdn2.microsoft.com/en-us/library/bb206304.aspx
原理参见第2点,使用方法参见第4点
附:
关于bumpmap图是可以直接程序创建的,下面给出该方法的代码(这是从 盖小房(BYOH)source code中看到的,直接贴这里可参考):
LPDIRECT3DTEXTURE9 CreateBumpMap(LPDIRECT3DDEVICE9 device, DWORD dwWidth, DWORD dwHeight,D3DFORMAT d3dBumpFormat ) { LPDIRECT3DTEXTURE9 psBumpMap;
// Create the bump map texture if( FAILED( device->CreateTexture( dwWidth, dwHeight, 1, 0/* Usage */, d3dBumpFormat, D3DPOOL_MANAGED,&psBumpMap,NULL ) ) ) return NULL;
// Lock the surface and write in some bumps for the waves D3DLOCKED_RECT d3dlr; psBumpMap->LockRect( 0, &d3dlr, 0, 0 ); CHAR* pDst = (CHAR*)d3dlr.pBits; CHAR iDu=0, iDv=0;
for( DWORD y=0; y<dwHeight; y++ ) { CHAR* pPixel = pDst; for( DWORD x=0; x<dwWidth; x++ ) { FLOAT fx = x/(FLOAT)dwWidth - 0.5f; FLOAT fy = y/(FLOAT)dwHeight - 0.5f; FLOAT r = sqrtf( fx*fx + fy*fy ); // iDu = (CHAR)( 32 * cosf( 300.0f * r ) * expf( -r * 5.0f ) ); iDu += (CHAR)( 128 * cosf( 100.0f * ( fx + fy ) ) ); // iDu += (CHAR)( 16 * cosf( 140.0f * ( fx * 0.85f - fy ) ) ); // iDv = (CHAR)( 32 * sinf( 300.0f * r ) * expf( -r * 5.0f ) ); iDv += (CHAR)( 128 * sinf( 100.0f * ( fx + fy ) ) ); // iDv += (CHAR)( 16 * sinf( 140.0f * ( fx * 0.85f - fy ) ) ); *pPixel++ = iDu; *pPixel++ = iDv; } pDst += d3dlr.Pitch; } psBumpMap->UnlockRect(0);
return psBumpMap; }
November 08 最近做的魔兽里区域选择显示图, 这个与地面贴花不一样,要求边框不会因为区域放大而跟着
缩放(与魔兽不一样的是中间不用小格子省点顶点), 而关于地面贴花可以用匹配地形网格再放绽放uv进行调整
并且设置边框模式或clamp模式(图片边框需透明)而简单得到,当然复杂的也可以用投影贴图来作,(类似于实时影子的作法:
先渲染场景深度,再调相机到灯光处渲染需需投影的物件到贴图上,最后将贴图以顶视图方式投影到地形上)

November 01
下面说说简单的hdr原理, 读取hdr文件 将颜色转到64位浮点原贴图中 将原贴图以1/4大小渲染到downsample贴图中(只取高光,即亮度低于1的被过滤掉) 对downsample进行横向和纵向blur
最后将blur与原贴图合成tone map, 即按比例混合在一起(并调整uv越近图中心的越亮,最后还进行高光指数pow) 最后的tone map就是最终的贴图了
另外bloom作法一般是类似的(只是可以不用精度浮点贴图):
渲染场景到原贴图
取出高亮部分(只取高光,即亮度在一定值以上)
blur 一下
最后与原贴图混合一下得出最终的tone map
uniform sampler2D texture; uniform float blurfactor; uniform float expfactor; const float cdelp = 0.001953125; uniform float sharpness;
float4 xposure(float4 cl,float e) { return ( exp(expfactor) - exp(expfactor-e)) * cl; }
void main( float2 texcoord : TEXCOORD0, out float4 finalColor : COLOR) { float delp = blurfactor* cdelp; float4 texColor = tex2D(texture, texcoord); float4 color = texColor*2.0 / 22.0; color += tex2D(texture,float2(texcoord.x+delp, texcoord.y+delp))*5.0 /22.0; color += tex2D(texture,float2(texcoord.x+delp, texcoord.y- delp))*5.0 /22.0; color += tex2D(texture,float2(texcoord.x- delp, texcoord.y- delp))*5.0 /22.0; color += tex2D(texture,float2(texcoord.x- delp, texcoord.y+delp))*5.0 /22.0; float e = color.r * 0.3 + color.g * 0.59 + color.b * 11; finalColor = xposure(texColor*sharpness + color*(1-sharpness),e); }
October 24
0 关于指令时间的问题
上次有兄弟问关于 指令时间的问题,答复查看 intel 手册是一个办法。 但很多人没有那个东东吧!,所以可以用另一招,在编译时加入 /Sc
选项:
ML /Fl /Sc Kinds.asm
还有有位兄弟问过 为什么 mov ax,offset table 比 lea ax,table 速度
要快?但到底快到什么程度,恐怕也没法感性认识。下面让偶们来
看看实际效果:
首先在源文件 Kinds.asm 中敲入:
data segment tabledw? data ends
code segment assume cs:code,ds:data start: push ds sub ax,ax push ax
mov ax,data mov ds,ax
mov ax,offset table lea ax,table
idiv table
retf code ends end start
保存后,控制台中敲入:
ML /Fl /Sc Kinds.asm
完成后,在同一目录下用记事本打开 Kinds.lst 文件:
0000 datasegment 0000 0000 tabledw? 0002 dataends
0000 codesegment assume cs:code,ds:data 0000start: 0000 10 1Epushds 0001 3 2B C0 subax,ax 0003 11 50 pushax
0004 4 B8 ---- Rmovax,data 0007 2 8E D8 movds,ax
0009 4 B8 0000 Rmovax,offset table 000C 8 8D 06 0000 R leaax,table
0010 177+ F7 3E 0000 R idivtable 0014 26 CB retf 0015 codeends endstart
可以清楚地看到 :
mov ds,ax 只需要 2个时钟周期 mov ax,offset table 需要 4个 lea ax,table 则需要 8 个 而 idiv table 更是夸张的用到了超过 177 个时钟周期。
是不是一目了然呢?呵呵!
1 debug中使用sal指令的问题
[问题]
在debug里面使用A指令,输入如下代码:
*************************** MOV AX,0ABC DEC AX AND AX,00FFH MOV CL,4 SAL AL,1
*************************** 当输入到 sal al,1 时提示error
[回答]
shl 与 sal 作用是完全一样的,所以在编译的时候自动将 sal 转换成了 shl .使用sal dubug 不识别,换成shl就搞定了。 可以把上述代码编译成 EXE 文件,然后用debug 中 u 指令查看,
结果 sal 的地方 被换成 shl。
2 看似 ''不可能'' 的汇编问题
[问题]
怎样用一条指令把BX的内容加上123,放在AX里?
[回答]
猛一看起来好像不可能,通常的做法是:
add bx,123
mov ax,bx
这至少要用到两条指令~~~要是mips机构的系统就好了,因为其中有
3参数指令:
addx $1,$2,100 ----- $1=$2+100
那么没办法了么?不是的!
想一下 lea 指令 ,呵呵~~~看一下如下的指令:
lea ax,[bx+123]
lea 取变量的偏移放入 ax 中,[] 代表变量是间接寻址,他的地址就等于[]
中的值,即 bx+123,这样就达到了题目的目的。
3 用移位指令来代替乘法指令
大家都知道可以用移位指令来做形如 2,4,8 等2的整次幂的乘法,
但是非整次幂呢?比如 乘10。其实很简单:
36 * 10 = 36 * (8 + 2) = 36 * 8 + 36 * 2 即等于: 24h * 8 + 24h * 2
接下来不用我讲了吧,这一方法也可以进一步推广。
4 察看 debug 状态寄存器
of(溢出) df(方向) if(中断) sf(符号) zf(零) af(辅助进位) pf(奇偶) cf(进位) 为一的时候 ov(OVerflow) dn(DowN) ei(Enable Interrupt) ng(NeGtive) zr(ZeRo) ac(Auxiliary Carry) pe(Parity Even) cy(CarrY) 为零的时候 nv(Not oVerflow) up(UP) di(DIsable interrupt) pl(PLus) nz(Not Zero) na(Not Auxiliary) po(Parity Odd) nc(Not Carry)
5 关于简单汇编环境的搭建
如果是老鸟,则随心所欲自由选择。我在这里只是给新手一些我的建议。
我一向反对新手一上来(毫无汇编编译经验)就使用汇编的集成开发环境比如
radasm之类,这样不但容易出错,而且不能真正了解编译器和连接器的底
层命令行用法。因为汇编本身编译就已经很简单了,不像C++之类有那么多
优化的东东,你再套一个花里胡哨的集成环境,对初学者岂不很累?
但我认为用一个带颜色标记的编辑器却是有必要的。
(比如简单的几句用记事本就很好,复杂的我推荐使用editplus2(别忘了要
下载汇编的语法文件。)
总的来说整个汇编环境是这样的:
16位dos程序: masm6.1x or nasm + editplus2
32位windows程序: masm32v9.0 or nasm + editplus2 + 一个资源编辑器
附, 上述的第2点解决初学者常碰到的下述问题: http://topic.csdn.net/t/20051008/15/4312328.html上述也解决了这样一个问题: 楼主wjk302(影子传说)2005-10-08 15:17:37 在 其他开发语言 / 汇编语言 提问 lea指令在win32汇编中问题 ebp的值就是指向堆栈的地址对吧,那么lea eax,[ebp] 就是得到ebp指向的堆栈内容的偏移地址, 和寄存器ebp的值是相同的么? 还有就是offset命令是相对于文件头的偏移地址,还是相对于整个寻址空间的偏移地址? 1 楼mydo(侯佩|hopy|ks)回复于 2005-10-08 15:58:40 得分 5和寄存器ebp的值是相同的么? yes! Top
2 楼wjk302(影子传说)回复于 2005-10-08 16:09:46 得分 0 1.如果和和寄存器ebp的值是相同的,那么 lea eax,[ebp] 等价于 mov eax,ebp ??? 2.offset命令是相对于文件头的偏移地址,还是相对于整个寻址空间的偏移地址??? Top
3 楼csdsjkk()回复于 2005-10-08 16:57:30 得分 5cpu 中没有文件的概念,当然是指地址空间了 Top
4 楼wjk302(影子传说)回复于 2005-10-08 17:07:04 得分 0 最后一点了 1.如果和和寄存器ebp的值是相同的,那么 lea eax,[ebp] 等价于 mov eax,ebp ??? Top
October 23 设备获取
#include <stdio.h> #include <windows.h> #include <setupapi.h> #include <devguid.h> #include <regstr.h>
#pragma comment(lib, "setupapi.lib")
int main( int argc, char *argv[ ], char *envp[ ] ) { HDEVINFO hDevInfo; SP_DEVINFO_DATA DeviceInfoData; DWORD i;
// Create a HDEVINFO with all present devices. hDevInfo = SetupDiGetClassDevs(NULL, 0, // Enumerator 0, DIGCF_PRESENT | DIGCF_ALLCLASSES ); if (hDevInfo == INVALID_HANDLE_VALUE) { // Insert error handling here. return 1; } // Enumerate through all devices in Set. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i, &DeviceInfoData);i++) { DWORD DataT; LPTSTR buffer = NULL; DWORD buffersize = 0; // // Call function with null to begin with, // then use the returned buffer size // to Alloc the buffer. Keep calling until // success or an unknown failure. // while (!SetupDiGetDeviceRegistryProperty( hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC, &DataT, (PBYTE)buffer, buffersize, &buffersize)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // Change the buffer size. if (buffer) LocalFree(buffer); buffer = (char*)LocalAlloc(LPTR,buffersize); } else { // Insert error handling here. break; } } printf("Result:[%s]\n",buffer); if (buffer) LocalFree(buffer); } if ( GetLastError()!=NO_ERROR && GetLastError()!=ERROR_NO_MORE_ITEMS ) { // Insert error handling here. return 1; } // Cleanup SetupDiDestroyDeviceInfoList(hDevInfo); return 0; } 在vc中调试汇编程序:
实现方法参见转来的几篇文章:
1. 贴个用VC++在源码级下调试MASM32汇编程序的方法。。。大家交流。。 (转) 摘自: http://www.pediy.com/bbshtml/bbs5/pediy50355.htm 标 题:贴个用VC++在源码级下调试MASM32汇编程序的方法。。。大家交流。。 (1千字) 发信人:Spring.W 时 间:2002-11-25 0:27:11 详细信息:
许多其它编译器都附带了源代码级的调试器,,这使得用这些高级语言调试比较简单,但对于masm并没有一个集成的开发和调试环境,我们可以用TRW和Softice实现源码级的调试,这两种方法,参看Hume兄的文章:http://www.finalseraph.org/hume/asmdata/sdbg.htm
下面提供一种用VC++6.0调试的方法,好像比前两种更简单些。
方法如下: -------- 1、将我们的汇编程序编译连接成调试模式: \masm32\bin\ml /c /coff /Cp /Zi Myprog.asm \masm32\bin\link /DEBUG /DEBUGTYPE:CV /subsystem:windows myProg.obj 2、用VC++6.0建立一个同ASM程序同名字的工程:myProg,并将它编译连接 成debug模式,此时,在VC工程myProg\debug中会形成myProg.exe。 3、将第1步骤中用Masm32编译连接成的同名exe文件myProg.exe拷贝到: VC++工程myProg\debug中,覆盖VC++形成myProg.exe 4、启动VC++6.0,打开myProg工程,build->start debug->go,呵呵。。 进入了Masm32形成的myProg.exe,并且是源码级调试。
至此,请随心所欲的用VC调试器的强大功能,调试你的Masm32程序吧!
附:我一般都是用个批处理(L_debug.bat)一下完成: c:\masm32\bin\ml /c /coff /Cp /Zi Myprog.asm >Mydebug.txt c:\masm32bin\link /DEBUG /DEBUGTYPE:CV /subsystem:windows myProg.obj copy .\myProg.exe VC工程\debug\myProg.exe 启动VC进行调试。。。
Spring.W 2002/11/25
2. 标 题: Myshell.asm的错误更正及在VC中融合masm32编译的方法 作 者: Spring.W 时 间: 2005-03-14,23:24 链 接: http://bbs.pediy.com/showthread.php?t=12067
有朋友来信说:Myshell.asm用TestVC测试时候,报告找不到文件,出错原因如下:
;---------------------------------------------- WJQ_PUSHA MACRO push ebx push ecx push edx push esi push edi push ebp pushfd ;;;这里原来是pushf,是16为的标志入栈,产生了错误 ENDM ;---------------------------------------------- WJQ_POPA MACRO popfd ;;;这里原来是popf,是16为的标志出栈,产生了错误 pop ebp pop edi pop esi pop edx pop ecx pop ebx ENDM ;----------------------------------------------
在此对各位朋友深表歉意!
另外: 介绍一种VC工程直接融合了MASM32汇编编译的方法: 这样可以直接在这个工程中对myshell.asm进行编译了连接了,而且也可以直接追踪到myshell.asm的源码中了。
方法如下: 1、将myshell.asm填加到VC工程的Source files中; 2、将Source files中的myshell.obj删除; 3、在Source files中的myshell.asm上:右键->Setting->选中Custom Build页 在Commands中输入: 如果是DEBUG模式,则输入: c:\masm32\bin\ml /c /coff /Zi /FoDEBUG\$(InputName).obj $(InputPath)
如果是RELEASE模式,则输入: c:\masm32\bin\ml /c /coff /FoRELEASE\$(InputName).obj $(InputPath)
在Outputs中输入: 如果是DEBUG模式,则输入: DEBUG\$(InputName).obj
如果是RELEASE模式,则输入: RELEASE\$(InputName).obj
如果您的没有把masm安装在c盘,则要作相应的修改。
之后,您可以直接对TestVC工程编译连接了。 ------------------------------------------------------------------------
再次谢谢各位朋友的来信! Spring.W 2005.3.15
3. 使用VC6调试器源码级调试win32汇编程序(转) 摘自: http://blog.csdn.net/hejiwen2001/archive/2005/06/16/395823.aspx 作者:溟初 本人拙笨,如有错误请批评指正,如有更好的方法或者技巧,欢迎互相交流。hejiwen2001@sohu.com.。 使用一个好的调试器无疑对学习win32汇编是至关重要的,本人更偏爱VC的强大调试环境,能否用VC调试器调试哪,于是从网上搜搜,找到一篇Spring.W的文章《贴个用VC++在源码级下调试MASM32汇编程序的方法。。。大家交流。。》,此文就是在此基础上的扩充。 编程环境:VC6.0,Masm32v8 方法如下: 1、 使用VC6新建一个空工程test(win32 console,win32 application等均可)。 2、 把汇编工程中的文件拷至新建工程目录下(hello.asm,makefile),并把这些文件加入工程中管理。 3、 配置IDE: (1)、tools/customize…/tools中添加一个工具nmake。在menu contens中添加一项nmake,Command中填入:nmake.exe,Initial Directory中填入: $(WkspDir),选中use output window。这样就在tools菜单下出现了一个新的菜单项nmake。可以把这个菜单项添加到工具栏中。 (2)、tools/option…/editor在save option中选中save befor running tools。 4、 制作makefile文件: EXE = test.exe #指定输出文件 OBJS = hello.obj #需要的目标文件 LINK_FLAG = /subsystem:windows /DEBUG /OUT:debug\test.exe #连接选项 #注: (1)/DEBUG必须存在 。 # (2)/OUT:debug\test.exe输出可执行文件名要与VC建立的工程名一致。 # (3)/subsystem:windows:如果是控制台程序,这里需要改为/subsystem:console ML_FLAG = /c /coff /Zi #编译选项 #注: /Zi必须存在 $(EXE): $(OBJS) Link $(LINK_FLAG) $(OBJS) .asm.obj: ml $(ML_FLAG) $< 5、点击菜单项tools/nmake,调用masm32中的ml,link进行编译连接程序。 至此就可以使用VC调试器源码级调试汇编程序了,可以设置断点,察看变量、内存、寄存器等,nmake出现语法错误时可以双击output window中的错误行定位到程序中的指定行,改代码时别忘了要用nmake编译。 注:变量最好不要以@开头定义,比如@num,这样的变量名无法再vc下察看。 参考: http://www.pediy.com/bbshtml/bbs5/pediy50355.htm 作者:Spring.W http://bbs.pediy.com/showthread.php?s=16dcabc8aa048f28da0e3d5b68712147&threadid=12067 作者:Spring.W http://www.aogosoft.com/bbs/mixpage.asp?mode=viewoktext&fileid=123 作者:crige http://asm.yeah.net 《Windows环境下32位汇编语言程序设计》pdf及代码 作者:罗云彬 附件:代码及配置图片(下载http://bbs.pediy.com/showthread.php?s=&threadid=14196)。 2005/6/2
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=395823
最近好些玩家的机器碰到0xC0000006: In page error这样的错误 我想知道这种错误有没有可能是我们程序bug造成的,还是系统查找页表出的问题.
如何解决. (如果您知道请留言,或是发email告诉我flipcode@msn.com,非常感谢!)
注:该问题已解决. 方法是采用了ryan的提议:自己读取贴图文件再用d3d的内存创建贴图.
这样经验证再没收到用户返回 的此类crash
flywind 13:41:30 关于MPRender::LoadTexture这个bug一直没能解决, 只知道是0xC0000006: In page error这样的错误, crash在d3d的函数中(D3DXCreateTextureFromFileEx)
flywind 13:43:31 查看到一些别人的程序也碰到这样的crash,但未见真正解决方案....: 1. KiXtart http://listes2.ac-nancy-metz.fr/wws/d_read/kheops/kixtart/Kix95.doc Make sure that you do not, in any way, disconnect or re-redirect the drive from which KIX32.EXE was started. Also, these faults can be caused by antivirus software. If you use antivirus software, make sure you are using the latest version and if the problem persists, test if disabling the antivirus software solves the problem. flywind 13:44:10
2. wow的: http://www.viker.org/bbs/39141-post1.html 我的WOW最近老是出现问题,重新装了也没用,你们看下,谁知道怎么解决的跟... This application has encountered a critical error: ERROR #132 (0x85100084) Fatal Exception Program: E:\World of Warcraft\WoW.exe Exception: 0xC0000006 (IN_PAGE_ERROR) at 001B:00656FFC
flywind 13:44:51 3. office 2003的: http://support.microsoft.com/kb/833267 症状 当您尝试设置或修复 Microsoft Office 2003 或 Microsoft Office XP 安装时,安装设置或修复可能会意外退出,并且不显示错误信息。
如果您检查安装日志文件,可能会看到与下列其中一项类似的项: Exception code:C0000006 IN_PAGE_ERROR Module:C:\WINDOWS\System32\msi.dll Function:0x7642452f Exception code:C0000006 IN_PAGE_ERROR Module:C:\WINDOWS\system32\IMAGEHLP.dll Function:0x76c94afa 注意:模块和函数可能不同。 回到顶端
原因 当您的操作系统已损坏时,或者您的硬盘驱动器有问题时,可能会发生此问题。
flywind 13:46:36 4. xHarbour 的: http://delphi.newswhat.com/geoxml/forumhistorythread?groupname=Advantage.Clipper&messageid=3f1cedfd@solutions.advantagedatabase.com 这个好象是在说同一个文件在网络共享使用时,可能会发生
张 13:47:14 说的都是页面访问错误
张 13:47:32 好像跟D3DXCreateTextureFromFileEx没有联系。
flywind 13:47:34 是的,第4个说的比较仔细
flywind 13:47:47 还举了一个例子
flywind 13:49:18 5. Eudora non responding http://eudorabb.qualcomm.com/showthread.php?t=3046 Hey
After recieving some email messages, I go to open one and the message window is opened and the message is displayed. But then I get a error message saying an "Unhandled exeption has occured" and Eudora just hangs until I go into Windows Task Manager and end the task.
I opened up the exception log and got the following ------------------------------------------------------------------------ Exception code: c0000006 IN_PAGE_ERROR Fault address: 7722790b 01:0007690b C:\WINDOWS\system32\WININET.dll
flywind 13:50:04 这个好象是说他打开时,别人正在用任务管理器结束了?
张 13:51:04 如果指针的值被错误的修改成进程用户地址范围以外的值(比如c0000006),都会出现访问违规的吧
flywind 13:51:22 违规访问,以前有,不是提示这个的
flywind 13:51:27 是访问非法
张 13:52:12 读取和写入都是一样的提示么?
flywind 13:52:23 是的
flywind 13:52:35 后面提示不一样,前面是一样的
flywind 13:53:29 是类似于这样的: 0xC0000005: Access violation writing location 0x101b88cc.
flywind 13:53:59 上面是写, 下面是读: 0xC0000005: Access violation reading location 0x000500b4.
flywind 13:55:15 0xC0000005 是访问非法的error code 0xc0000006 是分页/IO访问错误
张 14:02:51 访问一个内存地址,系统查找页表,如果对应得表项没有映射到内存或磁盘,可能就会出现这种错误。 flywind 14:08:32 嗯,前面一些文章说的是这样意思
|
|
|
|