opengl

hi i have been trying to run modern gl for couple days but had no luck

but someone on opengl irc helped me out and to never have to deal with this mess again here's the code
(i started from the original game demo)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#import "fmt.odin";
#import "math.odin";
#import "os.odin";
#import gl "opengl.odin";
#import win32 "sys/windows.odin";

main :: proc(){
	run();
}

win32_print_last_error :: proc() {
	err_code := cast(int)win32.GetLastError();
	if err_code != 0 {
		fmt.println("GetLastError: %", err_code);
	}
}

// Yuk!
to_c_string :: proc(s: string) -> []u8 {
	c_str := new_slice(u8, s.count+1);
	copy(c_str, cast([]byte)s);
	c_str[s.count] = 0;
	return c_str;
}


Window :: struct {
	width: int,
	height:      int,
	wc:                 win32.WNDCLASSEXA,
	dc:                 win32.HDC,
	hwnd:               win32.HWND,
	opengl_context: win32.HGLRC,
	 rc: win32.HGLRC,
	c_title:            []u8
}

make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) -> (Window, bool) {
	using win32;

	w: Window;
	w.width, w.height = msg, height;

	class_name := "Win32-Odin-Window\x00";
	c_class_name := class_name.data;
	if title[title.count-1] != 0 {
		w.c_title = to_c_string(title);
	} else {
		w.c_title = cast([]u8)title;
	}

	instance := GetModuleHandleA(nil);

	w.wc = WNDCLASSEXA{
		size       = cast(u32)size_of(WNDCLASSEXA),
		style      = CS_VREDRAW | CS_HREDRAW,
		instance   = cast(HINSTANCE)instance,
		class_name = c_class_name,
		wnd_proc   = window_proc,
	};

	if RegisterClassExA(^w.wc) == 0 {
		win32_print_last_error();
		return w, false;
	}

	w.hwnd = CreateWindowExA(0,
	                         c_class_name, w.c_title.data,
	                         WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
	                         CW_USEDEFAULT, CW_USEDEFAULT,
	                         cast(i32)w.width, cast(i32)w.height,
	                         nil, nil, instance, nil);

	if w.hwnd == nil {
		win32_print_last_error();
		return w, false;
	}

	w.dc = GetDC(w.hwnd);

	{
		pfd := PIXELFORMATDESCRIPTOR{
			size         = cast(u32)size_of(PIXELFORMATDESCRIPTOR),
			version      = 1,
			flags        = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
			pixel_type   = PFD_TYPE_RGBA,
			color_bits   = 32,
			alpha_bits   = 8,
			depth_bits   = 24,
			stencil_bits = 8,
			layer_type   = PFD_MAIN_PLANE,
		};

		SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil);
		w.opengl_context = wglCreateContext(w.dc);
		wglMakeCurrent(w.dc, w.opengl_context);

		attribs := [8]i32{
			//WGL_SAMPLES_ARB, 4,
			WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
			WGL_CONTEXT_MINOR_VERSION_ARB, 3,
			WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
			0, // NOTE(bill): tells the proc that this is the end of attribs
		};

		wglCreateContextAttribsARB := cast(wglCreateContextAttribsARBType)wglGetProcAddress((cast(string)"wglCreateContextAttribsARB\x00").data);
		w.rc = wglCreateContextAttribsARB(w.dc, nil, ^attribs[0]);
		wglMakeCurrent(w.dc, w.rc);
		SwapBuffers(w.dc);
	}

	return w, true;
}

destroy_window :: proc(w: ^Window) {
	free(w.c_title.data);
}

display_window :: proc(w: ^Window) {
	win32.SwapBuffers(w.dc);
}


run :: proc() {
	using win32;
	using math;

	win32_procA :: proc(hwnd: win32.HWND, msg: u32, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT #no_inline {
		if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
			os.exit(0);
			return 0;
		}
		return DefWindowProcA(hwnd, msg, wparam, lparam);
	}
	win32_proc := cast(WNDPROC)win32_procA;
	window, window_success := make_window("Odin gl Demo", 500, 450, win32_proc);
	if !window_success {
		return;
	}
	defer destroy_window(^window);

	//gl
	gl.init();

	vao : u32;
	gl.GenVertexArrays(1, ^vao);
	gl.BindVertexArray(vao);

	vertexData := []f32{
		-1,-1, 0,
		 1,-1, 0,
		 0, 1, 0
	};

	vertexBuffer : u32;
	gl.GenBuffers(1, ^vertexBuffer);
	gl.BindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
	gl.BufferData(gl.ARRAY_BUFFER, 9*size_of(f32)/* <-is there a better way?*/, vertexData.data, gl.STATIC_DRAW);

	//loop
	running := true;
	for running {
		msg: MSG;
		for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 {
			if msg.message == WM_QUIT {
				running = false;
			}
			TranslateMessage(^msg);
			DispatchMessageA(^msg);
		}
		//---------------------//
		gl.EnableVertexAttribArray(0);
		gl.BindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
		gl.VertexAttribPointer(0,3,gl.FLOAT,gl.FALSE,0,nil);
		gl.DrawArrays(gl.TRIANGLES,0,3);
		gl.DisableVertexAttribArray(0);

		//---------------------//
		display_window(^window);
	}
}

Edited by adekto on
For C code to set up modern GL context you can use this are reference: https://git.handmade.network/snippets/17
cool, il see what i can translate in next versions
i added shaders to it now but there are some aditions and changes i had to made to the opengl.odin file to make it work, might be doing some stuff wrong i will also include my modified gl file, i dont want to bother Bill about it since im probably missing stuff or doing the pointers wrong

hello triangle
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#import "fmt.odin";
#import "math.odin";
#import "os.odin";
#import gl "opengl.odin";
#import win32 "sys/windows.odin";

main :: proc(){
	run();
}

win32_print_last_error :: proc() {
	err_code := cast(int)win32.GetLastError();
	if err_code != 0 {
		fmt.println("GetLastError: %", err_code);
	}
}

// Yuk!
to_c_string :: proc(s: string) -> []u8 {
	c_str := new_slice(u8, s.count+1);
	copy(c_str, cast([]byte)s);
	c_str[s.count] = 0;
	return c_str;
}


Window :: struct {
	width: int,
	height:      int,
	wc:                 win32.WNDCLASSEXA,
	dc:                 win32.HDC,
	hwnd:               win32.HWND,
	opengl_context: win32.HGLRC,
	 rc: win32.HGLRC,
	c_title:            []u8
}

make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) -> (Window, bool) {
	using win32;

	w: Window;
	w.width, w.height = msg, height;

	class_name := "Win32-Odin-Window\x00";
	c_class_name := class_name.data;
	if title[title.count-1] != 0 {
		w.c_title = to_c_string(title);
	} else {
		w.c_title = cast([]u8)title;
	}

	instance := GetModuleHandleA(nil);

	w.wc = WNDCLASSEXA{
		size       = cast(u32)size_of(WNDCLASSEXA),
		style      = CS_VREDRAW | CS_HREDRAW,
		instance   = cast(HINSTANCE)instance,
		class_name = c_class_name,
		wnd_proc   = window_proc,
	};

	if RegisterClassExA(^w.wc) == 0 {
		win32_print_last_error();
		return w, false;
	}

	w.hwnd = CreateWindowExA(0,
	                         c_class_name, w.c_title.data,
	                         WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
	                         CW_USEDEFAULT, CW_USEDEFAULT,
	                         cast(i32)w.width, cast(i32)w.height,
	                         nil, nil, instance, nil);

	if w.hwnd == nil {
		win32_print_last_error();
		return w, false;
	}

	w.dc = GetDC(w.hwnd);

	{
		pfd := PIXELFORMATDESCRIPTOR{
			size         = cast(u32)size_of(PIXELFORMATDESCRIPTOR),
			version      = 1,
			flags        = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
			pixel_type   = PFD_TYPE_RGBA,
			color_bits   = 32,
			alpha_bits   = 8,
			depth_bits   = 24,
			stencil_bits = 8,
			layer_type   = PFD_MAIN_PLANE,
		};

		SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil);
		w.opengl_context = wglCreateContext(w.dc);
		wglMakeCurrent(w.dc, w.opengl_context);

		attribs := [8]i32{
			//WGL_SAMPLES_ARB, 4,
			WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
			WGL_CONTEXT_MINOR_VERSION_ARB, 3,
			WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
			0, // NOTE(bill): tells the proc that this is the end of attribs
		};

		wglCreateContextAttribsARB := cast(wglCreateContextAttribsARBType)wglGetProcAddress((cast(string)"wglCreateContextAttribsARB\x00").data);
		w.rc = wglCreateContextAttribsARB(w.dc, nil, ^attribs[0]);
		wglMakeCurrent(w.dc, w.rc);
		SwapBuffers(w.dc);
	}

	return w, true;
}

destroy_window :: proc(w: ^Window) {
	free(w.c_title.data);
}

display_window :: proc(w: ^Window) {
	win32.SwapBuffers(w.dc);
}


run :: proc() {
	using win32;
	using math;

	win32_procA :: proc(hwnd: win32.HWND, msg: u32, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT #no_inline {
		if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
			os.exit(0);
			return 0;
		}
		return DefWindowProcA(hwnd, msg, wparam, lparam);
	}
	win32_proc := cast(WNDPROC)win32_procA;
	window, window_success := make_window("Odin gl Demo", 500, 450, win32_proc);
	if !window_success {
		return;
	}
	defer destroy_window(^window);

	//gl
	gl.init();

	vao : u32;
	gl.GenVertexArrays(1, ^vao);
	gl.BindVertexArray(vao);



	vertexData := []f32{
		-1,-1, 0,/*<-vert color->*/1.0, 0.0, 0.0,
		 1,-1, 0,/*<-vert color->*/0.0, 1.0, 0.0,
		 0, 1, 0,/*<-vert color->*/0.0, 0.0, 1.0
	};

	vbo : u32;
	gl.GenBuffers(1, ^vbo);
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo);
	gl.BufferData(gl.ARRAY_BUFFER, vertexData.count*size_of(f32)/* <-is there a better way?*/, vertexData.data, gl.STATIC_DRAW);

	
	to_c_string :: proc(s: string) -> []byte {
		// no better way to do it :(
		c_str := new_slice(byte, s.count+1);
		copy(c_str, cast([]byte)s);
		c_str[s.count] = 0;
		return c_str;
	}
	check_shader :: proc(shader:u32){
		//check for shader error
		status :i32;
		gl.GetShaderiv(shader,gl.COMPILE_STATUS, ^status);
		fmt.println(status);
		buffer :=[512]byte{};
		gl.GetShaderInfoLog(shader,512,nil,^buffer[0]);
		if status == 0 {
			for i in buffer{
				fmt.printf("%c ",buffer[i]); //got no clue what its spitting out
			}
		}
		
		
	}

	//vertex shader
	vert := to_c_string("#version 430 core \n layout(location=0) in vec3 position; \n in vec3 color; \n out vec3 Color; \n void main(){ \n Color = color; \n gl_Position.xyz = position; \n gl_Position.w = 1; }");
	vertx := ^vert[0]; //not very eligant, any beter ways?
	vertShader := gl.CreateShader(gl.VERTEX_SHADER);
	gl.ShaderSource(vertShader, 1, ^vertx, nil);
	gl.CompileShader(vertShader);
	
	check_shader(vertShader);

	//fragment shader
	frag := to_c_string("#version 430 core \n uniform vec3 triangleColor; \n in vec3 Color; \n void main(){ \n  gl_FragColor = vec4(Color+triangleColor, 1.0); }");
	fragm := ^frag[0];
	fragShader := gl.CreateShader(gl.FRAGMENT_SHADER);
	gl.ShaderSource(fragShader, 1, ^fragm, nil);
	gl.CompileShader(fragShader);

	check_shader(fragShader);

	//program
	program := gl.CreateProgram();
	gl.AttachShader(program, vertShader);
	gl.AttachShader(program, fragShader);
	gl.LinkProgram(program);
	gl.UseProgram(program);

	colorptr := to_c_string("triangleColor");
	colorptrptr := colorptr[0];
	//changeColor := gl.GetUniformLocation(program, ^colorptrptr);
	//fmt.println(changeColor);
	changeColor := gl.GetUniformLocation(program, to_c_string("triangleColor"));
	gl.Uniform3f(changeColor, 0.0 ,0.5 ,0.1 );

	posAttrib := gl.GetAttribLocation(program, to_c_string("position"));
	gl.EnableVertexAttribArray(posAttrib);
	gl.VertexAttribPointer(posAttrib, 3 , gl.FLOAT, gl.FALSE, 6*size_of(f32), 0);

	colAttrib := gl.GetAttribLocation(program, to_c_string("color"));
	gl.EnableVertexAttribArray(colAttrib);
	
	gl.VertexAttribPointer(colAttrib, 3 , gl.FLOAT, gl.FALSE, 6*size_of(f32), 3*size_of(f32));


	//loop
	running := true;
	for running {
		msg: MSG;
		for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 {
			if msg.message == WM_QUIT {
				running = false;
			}
			TranslateMessage(^msg);
			DispatchMessageA(^msg);
		}
		gl.ClearColor(0,0.1,0.1,0);
		gl.Clear(gl.COLOR_BUFFER_BIT);
		//---------------------//
		//gl.EnableVertexAttribArray(0);
		//gl.BindBuffer(gl.ARRAY_BUFFER, vbo);
		//gl.VertexAttribPointer(0,3,gl.FLOAT,gl.FALSE,0,nil);
		gl.DrawArrays(gl.TRIANGLES,0,3);
		//gl.DisableVertexAttribArray(0);

		//---------------------//
		display_window(^window);
	}
}


opengl.odin
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#load "opengl_constants.odin";

Clear         :: proc(mask: u32)                                #foreign lib "glClear";
ClearColor    :: proc(r, g, b, a: f32)                          #foreign lib "glClearColor";
Begin         :: proc(mode: i32)                                #foreign lib "glBegin";
End           :: proc()                                         #foreign lib "glEnd";
Finish        :: proc()                                         #foreign lib "glFinish";
BlendFunc     :: proc(sfactor, dfactor: i32)                    #foreign lib "glBlendFunc";
Enable        :: proc(cap: i32)                                 #foreign lib "glEnable";
Disable       :: proc(cap: i32)                                 #foreign lib "glDisable";
GenTextures   :: proc(count: i32, result: ^u32)                 #foreign lib "glGenTextures";
DeleteTextures:: proc(count: i32, result: ^u32)                 #foreign lib "glDeleteTextures";
TexParameteri :: proc(target, pname, param: i32)                #foreign lib "glTexParameteri";
TexParameterf :: proc(target: i32, pname: i32, param: f32)      #foreign lib "glTexParameterf";
BindTexture   :: proc(target: i32, texture: u32)                #foreign lib "glBindTexture";
LoadIdentity  :: proc()                                         #foreign lib "glLoadIdentity";
Viewport      :: proc(x, y, width, height: i32)                 #foreign lib "glViewport";
Ortho         :: proc(left, right, bottom, top, near, far: f64) #foreign lib "glOrtho";
Color3f       :: proc(r, g, b: f32)                             #foreign lib "glColor3f";
Vertex3f      :: proc(x, y, z: f32)                             #foreign lib "glVertex3f";
TexCoord2f    :: proc(x,y: f32)									#foreign lib "glTexCoord2f";
TexImage2D    :: proc(target, level, internal_format,
                      width, height, border,
                      format, _type: i32, pixels: []f32) #foreign lib "glTexImage2D";

GetError    :: proc() -> i32            #foreign lib "glGetError";
GetString   :: proc(name: i32) -> ^byte #foreign lib "glGetString";
GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv";


string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; }

_libgl := win32.LoadLibraryA(string_data("opengl32.dll\x00"));

GetProcAddress :: proc(name: string) -> proc() #cc_c {
	assert(name[name.count-1] == 0);
	res := win32.wglGetProcAddress(name.data);
	if res == nil {
		res = win32.GetProcAddress(_libgl, name.data);
	}
	return res;
}

GenBuffers:       proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays:  proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers:      proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer:       proc(target: i32, buffer: u32) #cc_c;
BindVertexArray:  proc(buffer: u32) #cc_c;
BindSampler:      proc(position: i32, sampler: u32) #cc_c;
BufferData:       proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
BufferSubData:    proc(target: i32, offset, size: int, data: rawptr) #cc_c;

DrawArrays:       proc(mode, first: i32, count: u32) #cc_c;
DrawElements:     proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;

MapBuffer:        proc(target, access: i32) -> rawptr #cc_c;
UnmapBuffer:      proc(target: i32) #cc_c;

VertexAttribPointer:  proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: int) #cc_c;
EnableVertexAttribArray:  proc(index: u32) #cc_c;
DisableVertexAttribArray: proc(index: u32) #cc_c;
GetAttribLocation: proc(program: u32, name: []byte) -> u32 #cc_c;

CreateShader:   proc(shader_type: i32) -> u32 #cc_c;
ShaderSource:   proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
CompileShader:  proc(shader: u32) #cc_c;
CreateProgram:  proc() -> u32 #cc_c;
AttachShader:   proc(program, shader: u32) #cc_c;
DetachShader:   proc(program, shader: u32) #cc_c;
DeleteShader:   proc(shader:  u32) #cc_c;
LinkProgram:    proc(program: u32) #cc_c;
UseProgram:     proc(program: u32) #cc_c;
DeleteProgram:  proc(program: u32) #cc_c;


GetShaderiv:        proc(shader:  u32, pname: i32, params: ^i32) #cc_c;
GetProgramiv:       proc(program: u32, pname: i32, params: ^i32) #cc_c;
GetShaderInfoLog:   proc(shader:  u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
GetProgramInfoLog:  proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;

ActiveTexture:   proc(texture: i32) #cc_c;
GenerateMipmap:  proc(target:  i32) #cc_c;

SamplerParameteri:     proc(sampler: u32, pname: i32, param: i32) #cc_c;
SamplerParameterf:     proc(sampler: u32, pname: i32, param: f32) #cc_c;
SamplerParameteriv:    proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterfv:    proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
SamplerParameterIiv:   proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterIuiv:  proc(sampler: u32, pname: i32, params: ^u32) #cc_c;


Uniform1i:         proc(loc: i32, v0: i32) #cc_c;
Uniform2i:         proc(loc: i32, v0, v1: i32) #cc_c;
Uniform3i:         proc(loc: i32, v0, v1, v2: i32) #cc_c;
Uniform4i:         proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
Uniform1f:         proc(loc: i32, v0: f32) #cc_c;
Uniform2f:         proc(loc: i32, v0, v1: f32) #cc_c;
Uniform3f:         proc(loc: i32, v0, v1, v2: f32) #cc_c;
Uniform4f:         proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
UniformMatrix4fv:  proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;

GetUniformLocation:  proc(program: u32, name: []byte) -> i32 #cc_c;

init :: proc() {
	set_proc_address :: proc(p: rawptr, name: string) #inline { (cast(^(proc() #cc_c))p)^ = GetProcAddress(name); }

	set_proc_address(^GenBuffers,      "glGenBuffers\x00");
	set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
	set_proc_address(^GenSamplers,     "glGenSamplers\x00");
	set_proc_address(^BindBuffer,      "glBindBuffer\x00");
	set_proc_address(^BindSampler,     "glBindSampler\x00");
	set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
	set_proc_address(^BufferData,      "glBufferData\x00");
	set_proc_address(^BufferSubData,   "glBufferSubData\x00");

	set_proc_address(^DrawArrays,      "glDrawArrays\x00");
	set_proc_address(^DrawElements,    "glDrawElements\x00");

	set_proc_address(^MapBuffer,   "glMapBuffer\x00");
	set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");

	set_proc_address(^VertexAttribPointer,     "glVertexAttribPointer\x00");
	set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
	set_proc_address(^DisableVertexAttribArray, "glDisableVertexAttribArray\x00");
	set_proc_address(^GetAttribLocation, "glGetAttribLocation\x00");

	set_proc_address(^CreateShader,  "glCreateShader\x00");
	set_proc_address(^ShaderSource,  "glShaderSource\x00");
	set_proc_address(^CompileShader, "glCompileShader\x00");
	set_proc_address(^CreateProgram, "glCreateProgram\x00");
	set_proc_address(^AttachShader,  "glAttachShader\x00");
	set_proc_address(^DetachShader,  "glDetachShader\x00");
	set_proc_address(^DeleteShader,  "glDeleteShader\x00");
	set_proc_address(^LinkProgram,   "glLinkProgram\x00");
	set_proc_address(^UseProgram,    "glUseProgram\x00");
	set_proc_address(^DeleteProgram, "glDeleteProgram\x00");

	set_proc_address(^GetShaderiv,       "glGetShaderiv\x00");
	set_proc_address(^GetProgramiv,      "glGetProgramiv\x00");
	set_proc_address(^GetShaderInfoLog,  "glGetShaderInfoLog\x00");
	set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");

	set_proc_address(^ActiveTexture,  "glActiveTexture\x00");
	set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");

	set_proc_address(^Uniform1i, "glUniform1i\x00");
	set_proc_address(^Uniform2i, "glUniform2i\x00");
	set_proc_address(^Uniform3i, "glUniform3i\x00");
	set_proc_address(^Uniform4i, "glUniform4i\x00");
	set_proc_address(^Uniform1f, "glUniform1f\x00");
	set_proc_address(^Uniform2f, "glUniform2f\x00");
	set_proc_address(^Uniform3f, "glUniform3f\x00");
	set_proc_address(^Uniform4f, "glUniform4f\x00");
	set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");

	set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00");
	
	set_proc_address(^SamplerParameteri,    "glSamplerParameteri\x00");
	set_proc_address(^SamplerParameterf,    "glSamplerParameterf\x00");
	set_proc_address(^SamplerParameteriv,   "glSamplerParameteriv\x00");
	set_proc_address(^SamplerParameterfv,   "glSamplerParameterfv\x00");
	set_proc_address(^SamplerParameterIiv,  "glSamplerParameterIiv\x00");
	set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
}

Edited by adekto on
currently stuck cant seem to get texture to display also drawElements is cousing crashes not sure what exactly is going wrong since it compiles

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#import "fmt.odin";
#import "math.odin";
#import "os.odin";
#import gl "opengl.odin";
#import win32 "sys/windows.odin";

main :: proc(){
	run();
}

win32_print_last_error :: proc() {
	err_code := cast(int)win32.GetLastError();
	if err_code != 0 {
		fmt.println("GetLastError: %", err_code);
	}
}

// Yuk!
to_c_string :: proc(s: string) -> []u8 {
	c_str := new_slice(u8, s.count+1);
	copy(c_str, cast([]byte)s);
	c_str[s.count] = 0;
	return c_str;
}


Window :: struct {
	width: int,
	height:      int,
	wc:                 win32.WNDCLASSEXA,
	dc:                 win32.HDC,
	hwnd:               win32.HWND,
	opengl_context: win32.HGLRC,
	 rc: win32.HGLRC,
	c_title:            []u8
}

make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) -> (Window, bool) {
	using win32;

	w: Window;
	w.width, w.height = msg, height;

	class_name := "Win32-Odin-Window\x00";
	c_class_name := class_name.data;
	if title[title.count-1] != 0 {
		w.c_title = to_c_string(title);
	} else {
		w.c_title = cast([]u8)title;
	}

	instance := GetModuleHandleA(nil);

	w.wc = WNDCLASSEXA{
		size       = cast(u32)size_of(WNDCLASSEXA),
		style      = CS_VREDRAW | CS_HREDRAW,
		instance   = cast(HINSTANCE)instance,
		class_name = c_class_name,
		wnd_proc   = window_proc,
	};

	if RegisterClassExA(^w.wc) == 0 {
		win32_print_last_error();
		return w, false;
	}

	w.hwnd = CreateWindowExA(0,
	                         c_class_name, w.c_title.data,
	                         WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
	                         CW_USEDEFAULT, CW_USEDEFAULT,
	                         cast(i32)w.width, cast(i32)w.height,
	                         nil, nil, instance, nil);

	if w.hwnd == nil {
		win32_print_last_error();
		return w, false;
	}

	w.dc = GetDC(w.hwnd);

	{
		pfd := PIXELFORMATDESCRIPTOR{
			size         = cast(u32)size_of(PIXELFORMATDESCRIPTOR),
			version      = 1,
			flags        = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
			pixel_type   = PFD_TYPE_RGBA,
			color_bits   = 32,
			alpha_bits   = 8,
			depth_bits   = 24,
			stencil_bits = 8,
			layer_type   = PFD_MAIN_PLANE,
		};

		SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil);
		w.opengl_context = wglCreateContext(w.dc);
		wglMakeCurrent(w.dc, w.opengl_context);

		attribs := [8]i32{
			//WGL_SAMPLES_ARB, 4,
			WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
			WGL_CONTEXT_MINOR_VERSION_ARB, 3,
			WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
			0, // NOTE(bill): tells the proc that this is the end of attribs
		};

		wglCreateContextAttribsARB := cast(wglCreateContextAttribsARBType)wglGetProcAddress((cast(string)"wglCreateContextAttribsARB\x00").data);
		w.rc = wglCreateContextAttribsARB(w.dc, nil, ^attribs[0]);
		wglMakeCurrent(w.dc, w.rc);
		SwapBuffers(w.dc);
	}

	return w, true;
}

destroy_window :: proc(w: ^Window) {
	free(w.c_title.data);
}

display_window :: proc(w: ^Window) {
	win32.SwapBuffers(w.dc);
}


run :: proc() {
	using win32;
	using math;

	win32_procA :: proc(hwnd: win32.HWND, msg: u32, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT #no_inline {
		if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
			os.exit(0);
			return 0;
		}
		return DefWindowProcA(hwnd, msg, wparam, lparam);
	}
	win32_proc := cast(WNDPROC)win32_procA;
	window, window_success := make_window("Odin gl Demo", 500, 450, win32_proc);
	if !window_success {
		return;
	}
	defer destroy_window(^window);

	//gl
	gl.init();

	vao : u32;
	gl.GenVertexArrays(1, ^vao);
	gl.BindVertexArray(vao);



	vertexData := []f32{
		-1,-1, 0,/*<-vert color->*/1.0, 0.0, 0.0, /*texture->*/ 1,1,
		 1,-1, 0,/*<-vert color->*/0.0, 1.0, 0.0, /*texture->*/ 1,0,
		 0, 1, 0,/*<-vert color->*/0.0, 0.0, 1.0, /*texture->*/ 0,0
	};

	vbo : u32;
	gl.GenBuffers(1, ^vbo);
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo);
	gl.BufferData(gl.ARRAY_BUFFER, vertexData.count*size_of(f32)/* <-is there a better way?*/, vertexData.data, gl.STATIC_DRAW);

	
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
	
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

	pixels :=[]f32 {
		1.0, 0.0, 0.0,  1.0, 1.0, 1.0,
		1.0, 1.0, 1.0,  1.0, 0.0, 0.0
	};
	texture : u32;
	gl.GenTextures(1,^texture);
	gl.BindTexture(gl.TEXTURE_2D,texture);
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGB, 3, 3, 0, gl.RGB, gl.FLOAT , pixels);


	to_c_string :: proc(s: string) -> []byte {
		// no better way to do it :(
		c_str := new_slice(byte, s.count+1);
		copy(c_str, cast([]byte)s);
		c_str[s.count] = 0;
		return c_str;
	}
	check_shader :: proc(shader:u32){
		//check for shader error
		status :i32;
		gl.GetShaderiv(shader,gl.COMPILE_STATUS, ^status);
		fmt.println(status);
		buffer :=[512]byte{};
		gl.GetShaderInfoLog(shader,512,nil,^buffer[0]);
		if status == 0 {
			for i in buffer{
				fmt.printf("%c ",buffer[i]); //got no clue what its spitting out
			}
		}
		
		
	}

	//vertex shader
	vert := to_c_string("#version 430 core \n layout(location=0) in vec3 position; \n layout(location=1) in vec3 color; \n layout(location=2) in vec2 texCoord; \n out vec3 Color; \n out vec2 TexCoord; \n void main(){ \n Color = color; \n TexCoord = texCoord; \n gl_Position.xyz = position; \n gl_Position.w = 1; }");
	vertx := ^vert[0]; //not very eligant, any beter ways?
	vertShader := gl.CreateShader(gl.VERTEX_SHADER);
	gl.ShaderSource(vertShader, 1, ^vertx, nil);
	gl.CompileShader(vertShader);
	
	check_shader(vertShader);

	//fragment shader
	frag := to_c_string("#version 430 core \n uniform vec3 triangleColor; \n in vec3 Color; \n in vec2 TexCoord; \n uniform sampler2D Texture; \n void main(){ \n  gl_FragColor =  texture(Texture, TexCoord); //vec4(Color+triangleColor, 1.0); \n }");
	fragm := ^frag[0];
	fragShader := gl.CreateShader(gl.FRAGMENT_SHADER);
	gl.ShaderSource(fragShader, 1, ^fragm, nil);
	gl.CompileShader(fragShader);

	check_shader(fragShader);

	//program
	program := gl.CreateProgram();
	gl.AttachShader(program, vertShader);
	gl.AttachShader(program, fragShader);
	gl.LinkProgram(program);
	gl.UseProgram(program);

	colorptr := to_c_string("triangleColor");
	colorptrptr := colorptr[0];
	changeColor := gl.GetUniformLocation(program, to_c_string("triangleColor"));
	gl.Uniform3f(changeColor, 0.0 ,0.5 ,0.1 );

	Texture := gl.GetUniformLocation(program, to_c_string("Texture"));
	gl.Uniform1i(Texture, cast(i32)texture);

	posAttrib := gl.GetAttribLocation(program, to_c_string("position"));
	gl.EnableVertexAttribArray(posAttrib);
	gl.VertexAttribPointer(posAttrib, 3 , gl.FLOAT, gl.FALSE, 8*size_of(f32), 0);

	colAttrib := gl.GetAttribLocation(program, to_c_string("color"));
	gl.EnableVertexAttribArray(colAttrib);
	gl.VertexAttribPointer(colAttrib, 3 , gl.FLOAT, gl.FALSE, 8*size_of(f32), 3*size_of(f32));

	texAttrib := gl.GetAttribLocation(program, to_c_string("texCoord"));
	gl.EnableVertexAttribArray(texAttrib);
	gl.VertexAttribPointer(texAttrib, 2 , gl.FLOAT, gl.FALSE, 8*size_of(f32), 6*size_of(f32));


	//loop
	running := true;
	for running {
		msg: MSG;
		for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 {
			if msg.message == WM_QUIT {
				running = false;
			}
			TranslateMessage(^msg);
			DispatchMessageA(^msg);
		}
		gl.ClearColor(0,0.1,0.1,0);
		gl.Clear(gl.COLOR_BUFFER_BIT);
		//---------------------//
		gl.BindTexture(gl.TEXTURE_2D,texture);
		gl.BindVertexArray(vao);
		gl.DrawArrays(gl.TRIANGLES,0,3);
		//gl.DrawElements(gl.TRIANGLES,3,gl.UNSIGNED_INT /*crashes exe*/ , nil);
		gl.BindVertexArray(0);

		//---------------------//
		display_window(^window);
	}
}
your pixel data describes a 2x2 texture but you tell opengl it's a 3x3.

Also you should pass pixels.data instead of pixels.
oh ok, well fixed that but there still allot wrong
i got no idea what im doing at this point :p
most likely not the problem but you can pas the length of the shader sources explicitly so you don't need to null terminate them:

1
2
3
4
5
6
	vert := "#version 430 core \n layout(location=0) in vec3 position; \n layout(location=1) in vec3 color; \n layout(location=2) in vec2 texCoord; \n out vec3 Color; \n out vec2 TexCoord; \n void main(){ \n Color = color; \n TexCoord = texCoord; \n gl_Position.xyz = position; \n gl_Position.w = 1; }";
	vertx := vert.data; 
        length := vert.count; 
	vertShader := gl.CreateShader(gl.VERTEX_SHADER);
	gl.ShaderSource(vertShader, 1, ^vert.vertx, ^vert.count);
	gl.CompileShader(vertShader);


also after linkprogram you should check it analogue to checking the shader but instead with glGetProgramiv.
DrawElements crashes because you have not bound index buffer (GL_ELEMENT_ARRAY_BUFFER). It tries to deference array you passed which is NULL.

Also - add error checking (glGetError, GL_LINK_STATUS). And ideally use GL_ARB_debug_output extension. It should tell you this error (pointer NULL and no IB bound) in easy to understand message.

Edited by Mārtiņš Možeiko on