wined3d: Implement more GLSL instructions and a little cleanup.
[wine] / dlls / wined3d / arb_program_shader.c
1 /*
2  * Pixel and vertex shaders implementation using ARB_vertex_program
3  * and ARB_fragment_program GL extensions.
4  *
5  * Copyright 2002-2003 Jason Edmeades
6  * Copyright 2002-2003 Raphael Junqueira
7  * Copyright 2005 Oliver Stieber
8  * Copyright 2006 Ivan Gyurdiev
9  * Copyright 2006 Jason Green
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25
26 #include "config.h"
27
28 #include <math.h>
29 #include <stdio.h>
30
31 #include "wined3d_private.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
34
35 #define GLINFO_LOCATION      (*gl_info)
36
37 /********************************************************
38  * ARB_[vertex/fragment]_program helper functions follow
39  ********************************************************/
40
41 /** 
42  * Loads floating point constants into the currently set ARB_vertex/fragment_program.
43  * When @constants_set == NULL, it will load all the constants.
44  *  
45  * @target_type should be either GL_VERTEX_PROGRAM_ARB (for vertex shaders)
46  *  or GL_FRAGMENT_PROGRAM_ARB (for pixel shaders)
47  */
48 void shader_arb_load_constantsF(
49     WineD3D_GL_Info *gl_info,
50     GLuint target_type,
51     unsigned max_constants,
52     float* constants,
53     BOOL* constants_set) {
54
55     int i;
56     
57     for (i=0; i<max_constants; ++i) {
58         if (NULL == constants_set || constants_set[i]) {
59             TRACE("Loading constants %i: %f, %f, %f, %f\n", i,
60                   constants[i * sizeof(float) + 0], constants[i * sizeof(float) + 1],
61                   constants[i * sizeof(float) + 2], constants[i * sizeof(float) + 3]);
62
63             GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, &constants[i * sizeof(float)]));
64             checkGLcall("glProgramEnvParameter4fvARB");
65         }
66     }
67 }
68
69 /**
70  * Loads the app-supplied constants into the currently set ARB_[vertex/fragment]_programs.
71  * 
72  * We only support float constants in ARB at the moment, so don't 
73  * worry about the Integers or Booleans
74  */
75 void shader_arb_load_constants(
76     IWineD3DStateBlock* iface,
77     char usePixelShader,
78     char useVertexShader) {
79     
80     IWineD3DStateBlockImpl* stateBlock = (IWineD3DStateBlockImpl*) iface;
81     WineD3D_GL_Info *gl_info = &((IWineD3DImpl*)stateBlock->wineD3DDevice->wineD3D)->gl_info;
82
83     if (useVertexShader) {
84         IWineD3DVertexShaderImpl* vshader = (IWineD3DVertexShaderImpl*) stateBlock->vertexShader;
85         IWineD3DVertexDeclarationImpl* vertexDeclaration = 
86             (IWineD3DVertexDeclarationImpl*) vshader->vertexDeclaration;
87
88         if (NULL != vertexDeclaration && NULL != vertexDeclaration->constants) {
89             /* Load DirectX 8 float constants for vertex shader */
90             shader_arb_load_constantsF(gl_info, GL_VERTEX_PROGRAM_ARB,
91                                        WINED3D_VSHADER_MAX_CONSTANTS,
92                                        vertexDeclaration->constants, NULL);
93         }
94
95         /* Load DirectX 9 float constants for vertex shader */
96         shader_arb_load_constantsF(gl_info, GL_VERTEX_PROGRAM_ARB,
97                                    WINED3D_VSHADER_MAX_CONSTANTS,
98                                    stateBlock->vertexShaderConstantF,
99                                    stateBlock->set.vertexShaderConstantsF);
100     }
101
102     if (usePixelShader) {
103
104         /* Load DirectX 9 float constants for pixel shader */
105         shader_arb_load_constantsF(gl_info, GL_FRAGMENT_PROGRAM_ARB, WINED3D_PSHADER_MAX_CONSTANTS,
106                                    stateBlock->pixelShaderConstantF,
107                                    stateBlock->set.pixelShaderConstantsF);
108     }
109 }
110
111 /* Generate the variable & register declarations for the ARB_vertex_program output target */
112 void shader_generate_arb_declarations(
113     IWineD3DBaseShader *iface,
114     shader_reg_maps* reg_maps,
115     SHADER_BUFFER* buffer) {
116
117     IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
118     DWORD i;
119
120     for(i = 0; i < This->baseShader.limits.temporary; i++) {
121         if (reg_maps->temporary[i])
122             shader_addline(buffer, "TEMP R%lu;\n", i);
123     }
124
125     for (i = 0; i < This->baseShader.limits.address; i++) {
126         if (reg_maps->address[i])
127             shader_addline(buffer, "ADDRESS A%ld;\n", i);
128     }
129
130     for(i = 0; i < This->baseShader.limits.texcoord; i++) {
131         if (reg_maps->texcoord[i])
132             shader_addline(buffer,"TEMP T%lu;\n", i);
133     }
134
135     /* Texture coordinate registers must be pre-loaded */
136     for (i = 0; i < This->baseShader.limits.texcoord; i++) {
137         if (reg_maps->texcoord[i])
138             shader_addline(buffer, "MOV T%lu, fragment.texcoord[%lu];\n", i, i);
139     }
140
141     /* Need to PARAM the environment parameters (constants) so we can use relative addressing */
142     shader_addline(buffer, "PARAM C[%d] = { program.env[0..%d] };\n",
143                    This->baseShader.limits.constant_float,
144                    This->baseShader.limits.constant_float - 1);
145 }
146
147 /** Process the D3DSIO_DEF opcode into an ARB string - creates a local vec4
148  * float constant, and stores it's usage on the regmaps. */
149 void shader_hw_def(SHADER_OPCODE_ARG* arg) {
150
151     DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
152
153     shader_addline(arg->buffer, 
154                    "PARAM C%lu = { %f, %f, %f, %f };\n", reg,
155                    *((const float *)(arg->src + 0)),
156                    *((const float *)(arg->src + 1)),
157                    *((const float *)(arg->src + 2)),
158                    *((const float *)(arg->src + 3)) );
159
160     arg->reg_maps->constantsF[reg] = 1;
161 }
162
163
164 /* TODO: Add more ARB_[vertex/fragment]_program specific code here */