Why is my code not displaying on phone emulator with vertex array object in opengl - opengl-es

I'm new to this but what I'm trying to do is using vertex array object to display something on a phone emulator. But the problem is that it isn't displaying anything on the phone.
What I have understood of using vertex array objects is that a VAO is something like a folder that can points to different buffers and inside the VAO there is vertex buffer objects. What I have done in the code is create two buffers and a VAO. Bind the buffers to an array called mVBOIds. Then bind the VAO to it's own array then i setup the vertex with the buffers.
To populate these buffers I have a file named torus2.raw that has data that looks like this:
# Data order:
# Vertex
# Normal vector
# Texture coordinate
12.329425 0.0 -8.957851 1.0
-0.809017 1.0E-6 0.587785 0.0
0.05 1.0
Where we have the order of data, Vertex has 4 data, Normal Vector has 4 and then Texture coordinate has 2 data.
Here is the code for that part that creates the buffers and VAO and its inside the method onSurfaceCreated:
// Generate VBO Ids and load the VBOs with data
GLES30.glGenBuffers ( 2, mVBOIds, 0 );
GLES30.glBindBuffer ( GLES30.GL_ARRAY_BUFFER, mVBOIds[0] );
mVertices.position ( 0 );
GLES30.glBufferData ( GLES30.GL_ARRAY_BUFFER, mVertices.remaining() * 4,
mVertices, GLES30.GL_STATIC_DRAW );
GLES30.glBindBuffer ( GLES30.GL_ELEMENT_ARRAY_BUFFER, mVBOIds[1] );
mNormals.position ( 0 );
GLES30.glBufferData ( GLES30.GL_ELEMENT_ARRAY_BUFFER, 4 * mNormals.remaining(),
mNormals, GLES30.GL_STATIC_DRAW );
// Generate VAO Id
GLES30.glGenVertexArrays ( 1, mVAOId, 0 );
// Bind the VAO and then setup the vertex
// attributes
GLES30.glBindVertexArray ( mVAOId[0] );
GLES30.glBindBuffer ( GLES30.GL_ARRAY_BUFFER, mVBOIds[0] );
GLES30.glBindBuffer ( GLES30.GL_ELEMENT_ARRAY_BUFFER, mVBOIds[1] );
GLES30.glEnableVertexAttribArray (VERTEX_POS_INDX);
GLES30.glEnableVertexAttribArray (VERTEX_NORM_INDX);
GLES30.glVertexAttribPointer ( VERTEX_POS_INDX, VERTEX_POS_SIZE,
GLES30.GL_FLOAT, false, VERTEX_STRIDE,
0 );
GLES30.glVertexAttribPointer (VERTEX_NORM_INDX, VERTEX_NORM_SIZE,
GLES30.GL_FLOAT, false, VERTEX_STRIDE,
( VERTEX_POS_SIZE * 4 ) );
// Reset to the default VAO
GLES30.glBindVertexArray ( 0 );
GLES30.glClearColor ( 0.15f, 0.15f, 0.15f, 1.0f );
GLES30.glEnable(GLES30.GL_DEPTH_TEST);
After this when I have the buffer and VAO setup, I use onDrawFrame method to get it to show in display:
public void onDrawFrame ( GL10 glUnused )
{
// Initiate the model-view matrix as identity matrix
Matrix.setIdentityM(mViewMatrix, 0);
// Define a translation transformation
Matrix.translateM(mViewMatrix, 0, 0.0f, 0.0f, -60.0f);
// Define a rotation transformation
Matrix.rotateM(mViewMatrix, 0, 90.0f, 1.0f, 0.0f, 0.0f);
// Calculate the model-view and projection transformation as composite transformation
Matrix.multiplyMM (mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
// Clear the color buffer
GLES30.glClear ( GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT );
// Use the program object
GLES30.glUseProgram ( mProgramObject );
// Make MVP matrix accessible in the vertex shader
mMVPMatrixHandle = GLES30.glGetUniformLocation(mProgramObject, "uMVPMatrix");
GLES30.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Light position:
vLightPositionHandle = GLES30.glGetUniformLocation(mProgramObject, "vLightPosition");
GLES30.glUniform4fv(vLightPositionHandle, 1, lightPosition, 0);
// Light color:
vLightColorDfHandle = GLES30.glGetUniformLocation(mProgramObject, "vLightColorDf");
GLES30.glUniform4fv(vLightColorDfHandle, 1, lightColorDf, 0);
// Material color:
vMaterialColorDfHandle = GLES30.glGetUniformLocation(mProgramObject, "vMaterialColorDf");
GLES30.glUniform4fv(vMaterialColorDfHandle, 1, materialColorDf, 0);
GLES30.glBindVertexArray ( mVAOId[0] );
// Draw with the VAO settings
GLES30.glDrawElements ( GLES30.GL_TRIANGLES, mNormals.remaining(), GLES30.GL_UNSIGNED_SHORT, 0 );
// Return to the default VAO
GLES30.glBindVertexArray ( 0 );
}
But the problem is that I can't get anything to display. I've tried to double check the variabels, check if if the variabels are empty etc but I could not find the culprit. It could also be that I've understood the code differently and made a logical error but I can't see what it is. The result should be a blue-ish donut shaped model.
This is the whole code:
import android.content.Context;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import se.hig.dvg306.modul3app.tools.ResourceHandler;
public class Modul3Renderer implements GLSurfaceView.Renderer
{
//
// Constructor - loads model data from a res file and creates byte buffers for
// vertex data and for normal data
//
public Modul3Renderer (Context context)
{
appContext = context;
Log.e(TAG, "--->>> Creating ModelLoader...");
ModelLoader modelLoader = new ModelLoaderImpl ();
Log.e(TAG, "--->>> ...finished.");
Log.e(TAG, "--->>> Loading model...");
Log.e(TAG, "--->>> Starting with vertices...");
float[] mVerticesData; //= new float[0];
try {
mVerticesData = modelLoader.loadModel (context, R.raw.torus2, 0, 10, 0);
} catch (IOException e) {
throw new RuntimeException (e);
}
Log.e(TAG, "--->>> ...finished.");
// Process vertex data
// 4: because of 4 elements per vertex position
nbrOfVertices = mVerticesData.length / 10;
mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertices.put(mVerticesData).position(0);
Log.e(TAG, "--->>> Starting with normals...");
float[] mNormalData; //= new float[0];
try {
mNormalData = modelLoader.loadModel (context, R.raw.torus2, 4, 4, 6);
} catch (IOException e) {
throw new RuntimeException (e);
}
Log.e(TAG, "--->>> ...finished.");
// Process normal data
// 4: because of 4 elements per vertex position
nbrOfNormals = mNormalData.length / 4;
mNormals = ByteBuffer.allocateDirect(mNormalData.length * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mNormals.put(mNormalData).position(0);
}
///
// Create a shader object, load the shader source, and
// compile the shader.
//
private int createShader(int type, String shaderSrc )
{
int shader;
int[] compiled = new int[1];
// Create the shader object
shader = GLES30.glCreateShader ( type );
if ( shader == 0 )
{
return 0;
}
// Load the shader source
GLES30.glShaderSource ( shader, shaderSrc );
// Compile the shader
GLES30.glCompileShader ( shader );
// Check the compile status
GLES30.glGetShaderiv ( shader, GLES30.GL_COMPILE_STATUS, compiled, 0 );
if ( compiled[0] == 0 )
{
Log.e ( TAG, GLES30.glGetShaderInfoLog ( shader ) );
GLES30.glDeleteShader ( shader );
return 0;
}
return shader;
}
///
// Initialize the shader and program object
//
public void onSurfaceCreated ( GL10 glUnused, EGLConfig config )
{
int vertexShader;
int fragmentShader;
int programObject;
int[] linked = new int[1];
// Load the source code for the vertex shader program from a res file:
try {
vShaderStr = ResourceHandler.readTextData(appContext, R.raw.vertex_shader);
} catch (IOException e) {
Log.e ( TAG, "--->>> Could not load source code for vertex shader.");
throw new RuntimeException (e);
}
Log.e ( TAG, "--->>> Loaded vertex shader: " + vShaderStr);
// Load the source code for the fragment shader program from a res file:
try {
fShaderStr = ResourceHandler.readTextData(appContext, R.raw.fragment_shader);
} catch (IOException e) {
Log.e ( TAG, "--->>> Could not load source code for fragment shader.");
throw new RuntimeException (e);
}
Log.e ( TAG, "--->>> Loaded fragment shader: " + fShaderStr);
// Create the vertex/fragment shaders
vertexShader = createShader( GLES30.GL_VERTEX_SHADER, vShaderStr );
fragmentShader = createShader( GLES30.GL_FRAGMENT_SHADER, fShaderStr );
// Create the program object
programObject = GLES30.glCreateProgram();
if ( programObject == 0 )
{
return;
}
GLES30.glAttachShader ( programObject, vertexShader );
GLES30.glAttachShader ( programObject, fragmentShader );
// Bind vPosition to attribute 0
GLES30.glBindAttribLocation ( programObject, 0, "vPosition" );
// Bind vNormal to attribute 1
GLES30.glBindAttribLocation ( programObject, 1, "vNormal" );
// Link the program
GLES30.glLinkProgram ( programObject );
// Check the link status
GLES30.glGetProgramiv ( programObject, GLES30.GL_LINK_STATUS, linked, 0 );
if ( linked[0] == 0 )
{
Log.e ( TAG, "Error linking program:" );
Log.e ( TAG, GLES30.glGetProgramInfoLog ( programObject ) );
GLES30.glDeleteProgram ( programObject );
return;
}
// Store the program object
mProgramObject = programObject;
// Generate VBO Ids and load the VBOs with data
GLES30.glGenBuffers ( 2, mVBOIds, 0 );
GLES30.glBindBuffer ( GLES30.GL_ARRAY_BUFFER, mVBOIds[0] );
mVertices.position ( 0 );
GLES30.glBufferData ( GLES30.GL_ARRAY_BUFFER, mVertices.remaining() * 4,
mVertices, GLES30.GL_STATIC_DRAW );
GLES30.glBindBuffer ( GLES30.GL_ELEMENT_ARRAY_BUFFER, mVBOIds[1] );
mNormals.position ( 0 );
GLES30.glBufferData ( GLES30.GL_ELEMENT_ARRAY_BUFFER, 4 * mNormals.remaining(),
mNormals, GLES30.GL_STATIC_DRAW );
// Generate VAO Id
GLES30.glGenVertexArrays ( 1, mVAOId, 0 );
// Bind the VAO and then setup the vertex
// attributes
GLES30.glBindVertexArray ( mVAOId[0] );
GLES30.glBindBuffer ( GLES30.GL_ARRAY_BUFFER, mVBOIds[0] );
GLES30.glBindBuffer ( GLES30.GL_ELEMENT_ARRAY_BUFFER, mVBOIds[1] );
GLES30.glEnableVertexAttribArray (VERTEX_POS_INDX);
GLES30.glEnableVertexAttribArray (VERTEX_NORM_INDX);
GLES30.glVertexAttribPointer ( VERTEX_POS_INDX, VERTEX_POS_SIZE,
GLES30.GL_FLOAT, false, VERTEX_STRIDE,
0 );
GLES30.glVertexAttribPointer (VERTEX_NORM_INDX, VERTEX_NORM_SIZE,
GLES30.GL_FLOAT, false, VERTEX_STRIDE,
( VERTEX_POS_SIZE * 4 ) );
// Reset to the default VAO
GLES30.glBindVertexArray ( 0 );
GLES30.glClearColor ( 0.15f, 0.15f, 0.15f, 1.0f );
GLES30.glEnable(GLES30.GL_DEPTH_TEST);
}
//
// Draw a torus using the shader pair created in onSurfaceCreated()
//
public void onDrawFrame ( GL10 glUnused )
{
// Initiate the model-view matrix as identity matrix
Matrix.setIdentityM(mViewMatrix, 0);
// Define a translation transformation
Matrix.translateM(mViewMatrix, 0, 0.0f, 0.0f, -60.0f);
// Define a rotation transformation
Matrix.rotateM(mViewMatrix, 0, 90.0f, 1.0f, 0.0f, 0.0f);
// Calculate the model-view and projection transformation as composite transformation
Matrix.multiplyMM (mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
// Clear the color buffer
GLES30.glClear ( GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT );
// Use the program object
GLES30.glUseProgram ( mProgramObject );
// Make MVP matrix accessible in the vertex shader
mMVPMatrixHandle = GLES30.glGetUniformLocation(mProgramObject, "uMVPMatrix");
GLES30.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Light position:
vLightPositionHandle = GLES30.glGetUniformLocation(mProgramObject, "vLightPosition");
GLES30.glUniform4fv(vLightPositionHandle, 1, lightPosition, 0);
// Light color:
vLightColorDfHandle = GLES30.glGetUniformLocation(mProgramObject, "vLightColorDf");
GLES30.glUniform4fv(vLightColorDfHandle, 1, lightColorDf, 0);
// Material color:
vMaterialColorDfHandle = GLES30.glGetUniformLocation(mProgramObject, "vMaterialColorDf");
GLES30.glUniform4fv(vMaterialColorDfHandle, 1, materialColorDf, 0);
GLES30.glBindVertexArray ( mVAOId[0] );
// Draw with the VAO settings
GLES30.glDrawElements ( GLES30.GL_TRIANGLES, mNormals.remaining(), GLES30.GL_UNSIGNED_SHORT, 0 );
// Return to the default VAO
GLES30.glBindVertexArray ( 0 );
}
//
// Handle surface changes
//
public void onSurfaceChanged ( GL10 glUnused, int width, int height )
{
mWidth = width;
mHeight = height;
GLES30.glViewport(0, 0, width, height);
float ratio = (float) width / height;
// this projection matrix is applied to object coordinates
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1.0f, 1.0f, 0.5f, 1000.0f);
}
// Member variables
private Context appContext;
private int mWidth;
private int mHeight;
private int nbrOfVertices;
private FloatBuffer mVertices;
final int VERTEX_POS_SIZE = 4; // x, y and z
final int VERTEX_NORM_SIZE = 4; // r, g, b, and a
final int VERTEX_POS_INDX = 0;
final int VERTEX_NORM_INDX = 1;
private int [] mVBOIds = new int[2];
private int [] mVAOId = new int[1];
private int nbrOfNormals;
private FloatBuffer mNormals;
private int mProgramObject;
private int mMVPMatrixHandle;
// Transformation data:
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
final int VERTEX_STRIDE = ( 4 * ( VERTEX_POS_SIZE + VERTEX_NORM_SIZE ) );
// Light position and color (only diffuse term now):
private int vLightPositionHandle;
private final float lightPosition [] = {175.0f, 75.0f, 125.0f, 0.0f};
// Light color (only diffuse term now):
private int vLightColorDfHandle;
private final float lightColorDf [] = {0.98f, 0.98f, 0.98f, 1.0f};
// Material color (only diffuse term now):
private int vMaterialColorDfHandle;
private final float materialColorDf [] = {0.62f, 0.773f, 0.843f, 1.0f};
// To be read when creating the instance:
private String vShaderStr;
private String fShaderStr;
private static String TAG = "Modul3Renderer";
}

A GL_ELEMENT_ARRAY_BUFFER object is meant for the indices and should conitain integral data. You should use a GL_ARRAY_BUFFER for the normal vectors:
GLES30.glBindBuffer ( GLES30.GL_ARRAY_BUFFER, mVBOIds[1] );
mNormals.position ( 0 );
GLES30.glBufferData ( GLES30.GL_ARRAY_BUFFER, 4 * mNormals.remaining(),
mNormals, GLES30.GL_STATIC_DRAW );
When glVertexAttribPointer is called the buffer which is currently bound to the target ARRAY_BUFFER, is associated to the specified attribute index and the ID of the object is stored in the state vector of the currently bound VAO. So you have to bind the buffer object before calling glVertexAttribPointer:
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVBOIds[0]);
GLES30.glVertexAttribPointer ( VERTEX_POS_INDX, VERTEX_POS_SIZE,
GLES30.GL_FLOAT, false, VERTEX_STRIDE,
0 );
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVBOIds[1]);
GLES30.glVertexAttribPointer (VERTEX_NORM_INDX, VERTEX_NORM_SIZE,
GLES30.GL_FLOAT, false, VERTEX_STRIDE,
( VERTEX_POS_SIZE * 4 ) );

Related

How to let ControlP5 Dropodownlist open up instead of down?

Using this MWE from the documentation:
import controlP5.*;
import java.util.*;
ControlP5 cp5;
void setup() {
size(400, 400);
cp5 = new ControlP5(this);
List l = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
/* add a ScrollableList, by default it behaves like a DropdownList */
cp5.addScrollableList("dropdown")
.setPosition(100, 100)
.setSize(200, 100)
.setBarHeight(20)
.setItemHeight(20)
.addItems(l)
// .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
;
}
void draw() {
background(240);
}
How can I get the dropdownlist to open up instead of down? I'm trying to place the list towards the lower edge of my screen. I could not find an option in the documentation.
Because of ControlP5's use of Java Generics inheritance is actually quite tricky in this case should ScrollableListView's display() method be overriden:
ScrollableList extends Controller< ScrollableList >
in java a class can subclass a single class, not multiple, hence the customized subclass like PopUpScrollableList would inherit Controller< ScrollableList > , not Controller< PopUpScrollableList >
there are a bunch of properties accessed in ScrollableListView's display() which belong to ScrollableList which are either private or protected
TLDR;
#laancelot's suggestion to clone the library, modify the ScrollableListView's display() method directly and recompiling the library sounds like the easier option compared subclassing to a custom scroll list.
That being said, setting up an IDE and compiling a java library might not be the friendliest thing for a beginner, hence I can recommend a hacky workaround: simply shift the list's y position so it appears to be above instead of bellow:
import controlP5.*;
import java.util.*;
ControlP5 cp5;
ScrollableList list;
int listX = 100;
int listY = 100;
int listWidth = 200;
int listHeight = 100;
int barHeight = 20;
void setup() {
size(400, 400);
cp5 = new ControlP5(this);
List l = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
/* add a ScrollableList, by default it behaves like a DropdownList */
list = cp5.addScrollableList("dropdown")
.setPosition(listX, listY)
.setSize(listWidth, listHeight)
.setBarHeight(barHeight)
.setItemHeight(20)
.addItems(l)
// .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
;
}
void draw() {
// hack: shift the list up when it's open
if(list.isOpen()){
list.setPosition(listX, listY - listHeight + barHeight);
}else{
list.setPosition(listX, listY);
}
background(240);
}
It's not perfect visually, may be a potentially akward user experience, but it's the simplest option for this custom behaviour using ControlP5.
Alternatively it's worth looking at customising a different UI library or writin a custom list.
For the sake of argument, here's an modified version of the list example from theGuido library:
/**
* A list
*
*
* Make sure to try your scroll wheel!
*/
import de.bezier.guido.*;
Listbox listbox;
SimpleButton button;
Object lastItemClicked;
void setup ()
{
size(400, 400);
// make the manager
Interactive.make( this );
// create a list box
listbox = new Listbox( 20, 30, width-40, height-80 );
for ( int i = 0, r = int(10+random(100)); i < r; i++ )
{
listbox.addItem( "Item " + i );
}
listbox.visible = false;
// create button
button = new SimpleButton("pop-up list", 20, 350, width-40, 24 );
}
void draw ()
{
background( 20 );
listbox.visible = button.on;
if ( lastItemClicked != null )
{
fill( 255 );
text( "Clicked " + lastItemClicked.toString(), 30, 20 );
}
}
public void itemClicked ( int i, Object item )
{
lastItemClicked = item;
}
public class Listbox
{
float x, y, width, height;
ArrayList items;
int itemHeight = 20;
int listStartAt = 0;
int hoverItem = -1;
float valueY = 0;
boolean hasSlider = false;
boolean visible = true;
Listbox ( float xx, float yy, float ww, float hh )
{
x = xx; y = yy;
valueY = y;
width = ww; height = hh;
// register it
Interactive.add( this );
}
public void addItem ( String item )
{
if ( items == null ) items = new ArrayList();
items.add( item );
hasSlider = items.size() * itemHeight > height;
}
public void mouseMoved ( float mx, float my )
{
if(!visible){
return;
}
if ( hasSlider && mx > width-20 ) return;
hoverItem = listStartAt + int((my-y) / itemHeight);
}
public void mouseExited ( float mx, float my )
{
if(!visible){
return;
}
hoverItem = -1;
}
// called from manager
void mouseDragged ( float mx, float my )
{
if(!visible){
return;
}
if ( !hasSlider ) return;
if ( mx < x+width-20 ) return;
valueY = my-10;
valueY = constrain( valueY, y, y+height-20 );
update();
}
// called from manager
void mouseScrolled ( float step )
{
if(!visible){
return;
}
valueY += step;
valueY = constrain( valueY, y, y+height-20 );
update();
}
void update ()
{
if(!visible){
return;
}
float totalHeight = items.size() * itemHeight;
float itemsInView = height / itemHeight;
float listOffset = map( valueY, y, y+height-20, 0, totalHeight-height );
listStartAt = int( listOffset / itemHeight );
}
public void mousePressed ( float mx, float my )
{
if(!visible){
return;
}
if ( hasSlider && mx > width-20 ) return;
int item = listStartAt + int( (my-y) / itemHeight);
itemClicked( item, items.get(item) );
}
void draw ()
{
if(!visible){
return;
}
noStroke();
fill( 100 );
rect( x,y,this.width,this.height );
if ( items != null )
{
for ( int i = 0; i < int(height/itemHeight) && i < items.size(); i++ )
{
stroke( 80 );
fill( (i+listStartAt) == hoverItem ? 200 : 120 );
rect( x, y + (i*itemHeight), this.width, itemHeight );
noStroke();
fill( 0 );
text( items.get(i+listStartAt).toString(), x+5, y+(i+1)*itemHeight-5 );
}
}
if ( hasSlider )
{
stroke( 80 );
fill( 100 );
rect( x+width-20, y, 20, height );
fill( 120 );
rect( x+width-20, valueY, 20, 20 );
}
}
}
public class SimpleButton
{
float x, y, width, height;
boolean on;
String label = "";
SimpleButton ( float xx, float yy, float w, float h )
{
x = xx; y = yy; width = w; height = h;
Interactive.add( this ); // register it with the manager
}
SimpleButton ( String label, float xx, float yy, float w, float h )
{
this(xx, yy, w, h);
this.label = label;
}
// called by manager
void mousePressed ()
{
on = !on;
}
void draw ()
{
if ( on ) fill( 200 );
else fill( 100 );
rect(x, y, width, height);
if ( on ) fill( 100 );
else fill( 200 );
text(label, x + 10, y + this.height * 0.65);
}
}
The code is a lot more verbose in the sketch, but could be moved to a separate GUI tab.
Hopefully because it is simpler it can be manipulated easier than ControlP5 for custom behaviours.

Nuklear OpenGL flicker issue

I have downloaded the demo program for Nucklear in LWJGL, i've managed to compile it and have it to succesfully work. Then i've tried to implement the same code into my game engine and nothing shows up, unless i disable glClear(GL_COLOR_BUFFER_BIT). At that point i can see the little Nuklear window flickering.
This is my Window class
package Engine.Renderer;
import Engine.Messages.AppMsg;
import Engine.IntApplication;
import Engine.Messages.Type;
import Simulator.Application;
import org.lwjgl.nuklear.NkColorf;
import org.lwjgl.nuklear.NkMouse;
import org.lwjgl.opengl.*;
import org.lwjgl.system.Callback;
import org.lwjgl.system.MemoryStack;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.nuklear.Nuklear.*;
import static org.lwjgl.opengl.ARBDebugOutput.*;
import static org.lwjgl.opengl.ARBDebugOutput.GL_DEBUG_SEVERITY_LOW_ARB;
import static org.lwjgl.opengl.GL11C.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.*;
public class Window
{
public Window(int width, int height, String title)
{
m_Width = width;
m_Height = height;
m_Title = title;
if(!glfwInit())
{
///TODO: LOG
Runtime.getRuntime().exit(1);
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
m_Window = glfwCreateWindow(m_Width, m_Height, m_Title, NULL, NULL);
if(m_Window == NULL)
{
///TODO: LOG
Runtime.getRuntime().exit(1);
}
glfwMakeContextCurrent(m_Window);
GLCapabilities caps = GL.createCapabilities();
glfwShowWindow(m_Window);
Callback debugProc = GLUtil.setupDebugMessageCallback();
if (caps.OpenGL43) {
GL43.glDebugMessageControl(GL43.GL_DEBUG_SOURCE_API, GL43.GL_DEBUG_TYPE_OTHER, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, (IntBuffer)null, false);
} else if (caps.GL_KHR_debug) {
KHRDebug.glDebugMessageControl(
KHRDebug.GL_DEBUG_SOURCE_API,
KHRDebug.GL_DEBUG_TYPE_OTHER,
KHRDebug.GL_DEBUG_SEVERITY_NOTIFICATION,
(IntBuffer)null,
false
);
} else if (caps.GL_ARB_debug_output) {
glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_OTHER_ARB, GL_DEBUG_SEVERITY_LOW_ARB, (IntBuffer)null, false);
}
SetUpWindow();
renderer = new GUIRenderer();
}
public void Draw()
{
}
public void processEvents()
{
try (MemoryStack stack = stackPush()) {
IntBuffer w = stack.mallocInt(1);
IntBuffer h = stack.mallocInt(1);
glfwGetWindowSize(m_Window, w, h);
m_Width = w.get(0);
m_Height = h.get(0);
glfwGetFramebufferSize(m_Window, w, h);
m_DisplayWidth = w.get(0);
m_DisplayHeight = h.get(0);
}
nk_input_begin(NuklearContainer.ctx);
glfwPollEvents();
NkMouse mouse = NuklearContainer.ctx.input().mouse();
if (mouse.grab()) {
glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
} else if (mouse.grabbed()) {
float prevX = mouse.prev().x();
float prevY = mouse.prev().y();
glfwSetCursorPos(m_Window, prevX, prevY);
mouse.pos().x(prevX);
mouse.pos().y(prevY);
} else if (mouse.ungrab()) {
glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
nk_input_end(NuklearContainer.ctx);
try (MemoryStack stack = stackPush()) {
IntBuffer width = stack.mallocInt(1);
IntBuffer height = stack.mallocInt(1);
glfwGetWindowSize(m_Window, width, height);
glViewport(0, 0, width.get(0), height.get(0));
NkColorf bg = NkColorf.create().r(0.10f).g(0.18f).b(0.24f).a(1.0f);
glClearColor(bg.r(), bg.g(), bg.b(), bg.a());
}
//glClear(GL_COLOR_BUFFER_BIT);
renderer.Render();
glfwSwapBuffers(m_Window);
}
public void CleanUp()
{
glfwFreeCallbacks(m_Window);
glfwDestroyWindow(m_Window);
glfwTerminate();
}
private void SetUpWindow()
{
glfwSetKeyCallback(m_Window, (window, key, scancode, action, mods) ->
{
AppMsg msg = new AppMsg();
msg.key = key;
msg.scancode = scancode;
msg.mods = mods;
if(action == 0)
msg.type = Type.KEYUP;
if(action == 1)
msg.type = Type.KEYDOWN;
if(action == 2)
msg.type = Type.KEYREPEAT;
IntApplication.OnMsgProc(msg);
});
glfwSetMouseButtonCallback(m_Window, (window, button, action, mods) ->
{
AppMsg msg = new AppMsg();
msg.button = button;
msg.mods = mods;
if(action == 0)
msg.type = Type.MOUSEUP;
if(action == 1)
msg.type = Type.MOUSEDOWN;
Application.OnMsgProc(msg);
});
glfwSetCursorPosCallback(m_Window, (window, xpos, ypos) ->
{
AppMsg msg = new AppMsg();
msg.xpos = xpos;
msg.ypos = ypos;
msg.type = Type.MOUSEMOVE;
Application.OnMsgProc(msg);
});
glfwSetWindowCloseCallback(m_Window, (window) ->
IntApplication.OnClose());
nk_init(NuklearContainer.ctx, NuklearContainer.ALLOCATOR, null);
NuklearContainer.ctx.clip()
.copy((handle, text, len) -> {
if (len == 0) {
return;
}
try (MemoryStack stack = stackPush()) {
ByteBuffer str = stack.malloc(len + 1);
memCopy(text, memAddress(str), len);
str.put(len, (byte)0);
glfwSetClipboardString(m_Window, str);
}
})
.paste((handle, edit) -> {
long text = nglfwGetClipboardString(m_Window);
if (text != NULL) {
nnk_textedit_paste(edit, text, nnk_strlen(text));
}
});
}
private long m_Window;
static int m_Width, m_Height;
static int m_DisplayWidth, m_DisplayHeight;
private String m_Title;
GUIRenderer renderer;
}
And here is my GUIRender class
package Engine.Renderer;
import static org.lwjgl.nuklear.Nuklear.*;
import static org.lwjgl.opengl.GL20C.*;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
import static org.lwjgl.stb.STBTruetype.*;
import static org.lwjgl.stb.STBTruetype.stbtt_GetCodepointHMetrics;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.*;
import static org.lwjgl.system.MemoryUtil.memAddress;
import Engine.IOUtil;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Objects;
import org.lwjgl.nuklear.*;
import org.lwjgl.stb.STBTTAlignedQuad;
import org.lwjgl.stb.STBTTFontinfo;
import org.lwjgl.stb.STBTTPackContext;
import org.lwjgl.stb.STBTTPackedchar;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.Platform;
public class GUIRenderer extends Renderer
{
public GUIRenderer()
{
super();
try
{
this.ttf = IOUtil.ioResourceToByteBuffer("C:/Windows/Fonts/Arial.ttf", 512 * 1024);
} catch (IOException e)
{
throw new RuntimeException(e);
}
if (!m_Initialized)
Initialize();
try (MemoryStack stack = stackPush()) {
NkRect rect = NkRect.mallocStack(stack);
if (nk_begin(
NuklearContainer.ctx,
"Hello World",
nk_rect(50, 50, 230, 250, rect),
NK_WINDOW_BORDER | NK_WINDOW_NO_INPUT | NK_WINDOW_NO_INPUT | NK_WINDOW_NO_INPUT | NK_WINDOW_TITLE
)) {
nk_layout_row_static(NuklearContainer.ctx, 20, 80, 1);
nk_label(NuklearContainer.ctx, "background:", NK_TEXT_LEFT);
}
}
nk_end(NuklearContainer.ctx);
}
private void Initialize()
{
String NK_SHADER_VERSION = Platform.get() == Platform.MACOSX ? "#version 150\n" : "#version 300 es\n";
String vertex_shader =
NK_SHADER_VERSION +
"uniform mat4 ProjMtx;\n" +
"in vec2 Position;\n" +
"in vec2 TexCoord;\n" +
"in vec4 Color;\n" +
"out vec2 Frag_UV;\n" +
"out vec4 Frag_Color;\n" +
"void main() {\n" +
" Frag_UV = TexCoord;\n" +
" Frag_Color = Color;\n" +
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" +
"}\n";
String fragment_shader =
NK_SHADER_VERSION +
"precision mediump float;\n" +
"uniform sampler2D Texture;\n" +
"in vec2 Frag_UV;\n" +
"in vec4 Frag_Color;\n" +
"out vec4 Out_Color;\n" +
"void main(){\n" +
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" +
"}\n";
nk_buffer_init(NuklearContainer.cmds, NuklearContainer.ALLOCATOR, BUFFER_INITIAL_SIZE);
m_Program = glCreateProgram();
m_Vertex_Shader = glCreateShader(GL_VERTEX_SHADER);
m_Fragment_Shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(m_Vertex_Shader, vertex_shader);
glShaderSource(m_Fragment_Shader, fragment_shader);
glCompileShader(m_Vertex_Shader);
glCompileShader(m_Fragment_Shader);
if (glGetShaderi(m_Vertex_Shader, GL_COMPILE_STATUS) != GL_TRUE)
{
throw new IllegalStateException();
}
if (glGetShaderi(m_Fragment_Shader, GL_COMPILE_STATUS) != GL_TRUE)
{
throw new IllegalStateException();
}
glAttachShader(m_Program, m_Vertex_Shader);
glAttachShader(m_Program, m_Fragment_Shader);
glLinkProgram(m_Program);
if (glGetProgrami(m_Program, GL_LINK_STATUS) != GL_TRUE)
{
throw new IllegalStateException();
}
m_Uniform_Texture = glGetUniformLocation(m_Program, "Texture");
m_Uniform_Proj = glGetUniformLocation(m_Program, "ProjMtx");
int attrib_pos = glGetAttribLocation(m_Program, "Position");
int attrib_uv = glGetAttribLocation(m_Program, "TexCoord");
int attrib_col = glGetAttribLocation(m_Program, "Color");
{
// buffer setup
m_Vbo = glGenBuffers();
m_Ebo = glGenBuffers();
m_Vao = glGenVertexArrays();
glBindVertexArray(m_Vao);
glBindBuffer(GL_ARRAY_BUFFER, m_Vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Ebo);
glEnableVertexAttribArray(attrib_pos);
glEnableVertexAttribArray(attrib_uv);
glEnableVertexAttribArray(attrib_col);
glVertexAttribPointer(attrib_pos, 2, GL_FLOAT, false, 20, 0);
glVertexAttribPointer(attrib_uv, 2, GL_FLOAT, false, 20, 8);
glVertexAttribPointer(attrib_col, 4, GL_UNSIGNED_BYTE, true, 20, 16);
}
{
// null texture setup
int nullTexID = glGenTextures();
NuklearContainer.null_texture.texture().id(nullTexID);
NuklearContainer.null_texture.uv().set(0.5f, 0.5f);
glBindTexture(GL_TEXTURE_2D, nullTexID);
try (MemoryStack stack = stackPush())
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, stack.ints(0xFFFFFFFF));
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
FontInit();
}
private void FontInit()
{
int BITMAP_W = 1024;
int BITMAP_H = 1024;
int FONT_HEIGHT = 18;
int fontTexID = glGenTextures();
STBTTFontinfo fontInfo = STBTTFontinfo.create();
STBTTPackedchar.Buffer cdata = STBTTPackedchar.create(95);
float scale;
float descent;
try (MemoryStack stack = stackPush()) {
stbtt_InitFont(fontInfo, ttf);
scale = stbtt_ScaleForPixelHeight(fontInfo, FONT_HEIGHT);
IntBuffer d = stack.mallocInt(1);
stbtt_GetFontVMetrics(fontInfo, null, d, null);
descent = d.get(0) * scale;
ByteBuffer bitmap = memAlloc(BITMAP_W * BITMAP_H);
STBTTPackContext pc = STBTTPackContext.mallocStack(stack);
stbtt_PackBegin(pc, bitmap, BITMAP_W, BITMAP_H, 0, 1, NULL);
stbtt_PackSetOversampling(pc, 4, 4);
stbtt_PackFontRange(pc, ttf, 0, FONT_HEIGHT, 32, cdata);
stbtt_PackEnd(pc);
// Convert R8 to RGBA8
ByteBuffer texture = memAlloc(BITMAP_W * BITMAP_H * 4);
for (int i = 0; i < bitmap.capacity(); i++) {
texture.putInt((bitmap.get(i) << 24) | 0x00FFFFFF);
}
texture.flip();
glBindTexture(GL_TEXTURE_2D, fontTexID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, BITMAP_W, BITMAP_H, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
memFree(texture);
memFree(bitmap);
}
NuklearContainer.default_font
.width((handle, h, text, len) -> {
float text_width = 0;
try (MemoryStack stack = stackPush()) {
IntBuffer unicode = stack.mallocInt(1);
int glyph_len = nnk_utf_decode(text, memAddress(unicode), len);
int text_len = glyph_len;
if (glyph_len == 0) {
return 0;
}
IntBuffer advance = stack.mallocInt(1);
while (text_len <= len && glyph_len != 0) {
if (unicode.get(0) == NK_UTF_INVALID) {
break;
}
/* query currently drawn glyph information */
stbtt_GetCodepointHMetrics(fontInfo, unicode.get(0), advance, null);
text_width += advance.get(0) * scale;
/* offset next glyph */
glyph_len = nnk_utf_decode(text + text_len, memAddress(unicode), len - text_len);
text_len += glyph_len;
}
}
return text_width;
})
.height(FONT_HEIGHT)
.query((handle, font_height, glyph, codepoint, next_codepoint) -> {
try (MemoryStack stack = stackPush()) {
FloatBuffer x = stack.floats(0.0f);
FloatBuffer y = stack.floats(0.0f);
STBTTAlignedQuad q = STBTTAlignedQuad.mallocStack(stack);
IntBuffer advance = stack.mallocInt(1);
stbtt_GetPackedQuad(cdata, BITMAP_W, BITMAP_H, codepoint - 32, x, y, q, false);
stbtt_GetCodepointHMetrics(fontInfo, codepoint, advance, null);
NkUserFontGlyph ufg = NkUserFontGlyph.create(glyph);
ufg.width(q.x1() - q.x0());
ufg.height(q.y1() - q.y0());
ufg.offset().set(q.x0(), q.y0() + (FONT_HEIGHT + descent));
ufg.xadvance(advance.get(0) * scale);
ufg.uv(0).set(q.s0(), q.t0());
ufg.uv(1).set(q.s1(), q.t1());
}
})
.texture(it -> it
.id(fontTexID));
nk_style_set_font(NuklearContainer.ctx, NuklearContainer.default_font);
}
public void Render()
{
try (MemoryStack stack = stackPush())
{
// setup global state
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glActiveTexture(GL_TEXTURE0);
// setup program
glUseProgram(m_Program);
glUniform1i(m_Uniform_Texture, 0);
glUniformMatrix4fv(m_Uniform_Proj, false, stack.floats(
2.0f / Window.m_Width, 0.0f, 0.0f, 0.0f,
0.0f, -2.0f / Window.m_Height, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f
));
glViewport(0, 0, Window.m_DisplayWidth, Window.m_DisplayHeight);
}
{
// convert from command queue into draw list and draw to screen
// allocate vertex and element buffer
glBindVertexArray(m_Vao);
glBindBuffer(GL_ARRAY_BUFFER, m_Vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Ebo);
glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, GL_STREAM_DRAW);
// load draw vertices & elements directly into vertex + element buffer
ByteBuffer vertices = Objects.requireNonNull(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY, max_vertex_buffer, null));
ByteBuffer elements = Objects.requireNonNull(glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY, max_element_buffer, null));
try (MemoryStack stack = stackPush())
{
// fill convert configuration
NkConvertConfig config = NkConvertConfig.callocStack(stack)
.vertex_layout(VERTEX_LAYOUT)
.vertex_size(20)
.vertex_alignment(4)
.null_texture(NuklearContainer.null_texture)
.circle_segment_count(22)
.curve_segment_count(22)
.arc_segment_count(22)
.global_alpha(1.0f)
.shape_AA(NK_ANTI_ALIASING_ON)
.line_AA(NK_ANTI_ALIASING_ON);
// setup buffers to load vertices and elements
NkBuffer vbuf = NkBuffer.mallocStack(stack);
NkBuffer ebuf = NkBuffer.mallocStack(stack);
nk_buffer_init_fixed(vbuf, vertices/*, max_vertex_buffer*/);
nk_buffer_init_fixed(ebuf, elements/*, max_element_buffer*/);
nk_convert(NuklearContainer.ctx, NuklearContainer.cmds, vbuf, ebuf, config);
}
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
glUnmapBuffer(GL_ARRAY_BUFFER);
// iterate over and execute each draw command
float fb_scale_x = (float) Window.m_DisplayWidth / (float) Window.m_Width;
float fb_scale_y = (float) Window.m_DisplayHeight / (float) Window.m_Height;
long offset = NULL;
for (NkDrawCommand cmd = nk__draw_begin(NuklearContainer.ctx, NuklearContainer.cmds); cmd != null; cmd = nk__draw_next(cmd, NuklearContainer.cmds, NuklearContainer.ctx))
{
if (cmd.elem_count() == 0)
{
continue;
}
glBindTexture(GL_TEXTURE_2D, cmd.texture().id());
glScissor(
(int) (cmd.clip_rect().x() * fb_scale_x),
(int) ((Window.m_Height - (int) (cmd.clip_rect().y() + cmd.clip_rect().h())) * fb_scale_y),
(int) (cmd.clip_rect().w() * fb_scale_x),
(int) (cmd.clip_rect().h() * fb_scale_y)
);
glDrawElements(GL_TRIANGLES, cmd.elem_count(), GL_UNSIGNED_SHORT, offset);
offset += cmd.elem_count() * 2;
}
nk_clear(NuklearContainer.ctx);
}
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glDisable(GL_BLEND);
glDisable(GL_SCISSOR_TEST);
}
private boolean m_Initialized;
public boolean IsInitialized() { return m_Initialized; }
private int BUFFER_INITIAL_SIZE = 4 * 1024;
long max_vertex_buffer = 512 * 1024;
long max_element_buffer = 128 * 1024;
private NkDrawVertexLayoutElement.Buffer VERTEX_LAYOUT = NkDrawVertexLayoutElement.create(4)
.position(0).attribute(NK_VERTEX_POSITION).format(NK_FORMAT_FLOAT).offset(0)
.position(1).attribute(NK_VERTEX_TEXCOORD).format(NK_FORMAT_FLOAT).offset(8)
.position(2).attribute(NK_VERTEX_COLOR).format(NK_FORMAT_R8G8B8A8).offset(16)
.position(3).attribute(NK_VERTEX_ATTRIBUTE_COUNT).format(NK_FORMAT_COUNT).offset(0)
.flip();
private ByteBuffer ttf;
}
I'm really sorry if the code is huge, but even just the GLFWDemo is 600+ lines long.

How can I create Direct3d 11 renderer using SDL 2.0.9

In my project I must use SDL_BLENDOPERATION_MAXIMUM via SDL_ComposeCustomBlendMode() which is supported in SDL 2.0.9 by direct3d11 renderer only. I have Windows 8.1 and GeForce GTX750 Ti with updated drivers. My system should support DirectX 11 renderending.
Changing defines in SDL_config.h or SDL_config_windows.h (SDL_VIDEO_RENDER_D3D11 to 1 and SDL_VIDEO_RENDER_D3D to 0) doesn't help.
I tried to fill preprocessor difinitions with defines SDL_VIDEO_RENDER_D3D11 or WINRT according to SDL source code. But it doesn't help.
What should I do to activate direct3d11 renderer so I can use blend mode max?
My test code:
#include "SDL.h"
#include "SDL_image.h"
#include <string>
using namespace std;
int main( int argc, char *argv[] ) {
SDL_Init( SDL_INIT_VIDEO );
IMG_Init( IMG_INIT_PNG );
SDL_SetHintWithPriority( SDL_HINT_RENDER_DRIVER, "direct3d11", SDL_HINT_OVERRIDE );
SDL_Window *window = SDL_CreateWindow( "Testing", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
1200, 600, SDL_WINDOW_RESIZABLE );
SDL_Renderer *renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED );
SDL_RendererInfo *rendererInfo = new SDL_RendererInfo();
SDL_RendererInfo *driverInfo = new SDL_RendererInfo();
SDL_GetRendererInfo( renderer, rendererInfo );
int drivers = SDL_GetNumRenderDrivers();
string availableDrivers = " (";
for ( int i = 0; i < drivers; ++i ) {
SDL_GetRenderDriverInfo( i, driverInfo );
string driverName = driverInfo->name;
if ( i == drivers - 1 ) {
availableDrivers += driverName;
}
else {
availableDrivers += driverName + ", ";
}
}
availableDrivers += ")";
string path = SDL_GetBasePath();
SDL_Surface *surfRed = IMG_Load( (path + "\\Red.png").c_str() );
SDL_Texture *textRed = SDL_CreateTextureFromSurface( renderer, surfRed );
SDL_FreeSurface( surfRed );
SDL_Surface *surfBlue = IMG_Load( ( path + "\\Blue.png" ).c_str() );
SDL_Texture *textBlue = SDL_CreateTextureFromSurface( renderer, surfBlue );
SDL_FreeSurface( surfBlue );
SDL_Rect destRed, destBlue;
destRed.x = 128;
destRed.y = 128;
destBlue.x = 196;
destBlue.y = 196;
SDL_QueryTexture( textRed, NULL, NULL, &destRed.w, &destRed.h );
SDL_QueryTexture( textBlue, NULL, NULL, &destBlue.w, &destBlue.h );
SDL_BlendMode blendMode = SDL_ComposeCustomBlendMode( SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_MAXIMUM,
SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_MAXIMUM );
SDL_SetTextureBlendMode( textRed, blendMode );
SDL_SetTextureBlendMode( textBlue, blendMode );
// SDL_SetRenderDrawBlendMode( renderer, blendMode );
string info = rendererInfo->name + availableDrivers + " " + SDL_GetError();
SDL_SetWindowTitle( window, info.c_str() );
SDL_SetRenderDrawColor( renderer, 0, 0, 0, 255 );
SDL_Event event;
bool isRunning = true;
while ( isRunning ) {
if ( SDL_PollEvent( &event ) ) {
if ( event.type == SDL_QUIT ) {
isRunning = false;
}
}
SDL_RenderClear( renderer );
SDL_RenderCopy( renderer, textRed, NULL, &destRed );
SDL_RenderCopy( renderer, textBlue, NULL, &destBlue );
SDL_RenderPresent( renderer );
}
delete driverInfo;
delete rendererInfo;
SDL_DestroyTexture( textRed );
SDL_DestroyTexture( textBlue );
SDL_DestroyRenderer( renderer );
SDL_DestroyWindow( window );
IMG_Quit();
SDL_Quit();
return 0;
}
Window title is "direct3d (direct3d, opengl, opengles2, software) This operration is not supported". It works fine when I change to SDL_BLENDOPERATION_ADD, but it's not what I want. If I uncomment renderer blend mode it doesn't help too.
Enumerate the supported renderer backends via SDL_GetNumRenderDrivers() and SDL_GetRenderDriverInfo().
Note the index of the direct3d11 driver, if it exists.
Pass index into SDL_CreateRenderer().
All together:
SDL_Init( SDL_INIT_VIDEO );
SDL_Window* window = SDL_CreateWindow( "SDL2", 0, 0, 640, 480, SDL_WINDOW_SHOWN );
SDL_Renderer* renderer = nullptr;
for( int i = 0; i < SDL_GetNumRenderDrivers(); ++i )
{
SDL_RendererInfo rendererInfo = {};
SDL_GetRenderDriverInfo( i, &rendererInfo );
if( rendererInfo.name != std::string( "direct3d11" ) )
{
continue;
}
renderer = SDL_CreateRenderer( window, i, 0 );
break;
}
Note that what you are setting with SDL_VIDEO_RENDER_D3D and friends are compile time definitions for building SDL with D3D support.
To do this at runtime:
Sometime after SDL_Init() and before creating your window/renderer set a hint for it.
// returns true on success or false on failure
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "direct3d11");
However, this will only work on Windows, and I believe d3d is already the default renderer for windows. If your version of windows supports d3d11 that is what SDL should use. I strongly suspect you already have a d3d11 renderer and your problem is with how you instantiate or use your custom blend mode.
To verify you have a d3d11 renderer:
SDL_RendererInfo info;
SDL_GetRendererInfo(renderer, &info);
printf("%s", info.name);
To create a custom blend mode with SDL_BLENDOPERATION_MAXIMUM
SDL_BlendMode blender = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_SRC_ALPHA, // change this to suit your needs
SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, // change this to suit your needs
SDL_BLENDOPERATION_MAXIMUM,
SDL_BLENDFACTOR_ONE, // change this to suit your needs
SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, // change this to suit your needs
SDL_BLENDOPERATION_MAXIMUM);
SDL_SetTextureBlendMode(texture, blender); // blender is your custom mode
SDL_SetRenderDrawBlendMode(renderer, blender); // blender is your custom mode
I cant imagine the above blender is actually the combination of factors/operations you want, but you didn't post your actual code to work off.

HLSL Stream Out Entries don't work correctly

I want implement Particle system based on stream out structure to my bigger project. I saw few articles about that method and I build one particle. It works almost correctly but in geometry shader with stream out i cant get value of InitVel.z and age because it always is 0. If i change order of age(for example age is before Position) it works fine for age but 6th float of order is still 0. It looks like he push only 5 first positions. I had no idea what i do wrong because i try change almost all(create input layout for vertex, the same like entry SO Declaration, change number of strides for static 28, change it to 32 but in this case he draw chaotic so size of strides is probably good). I think it is problem with limits of NumEntry in declaration Entry but on site msdn i saw the limit for directx is D3D11_SO_STREAM_COUNT(4)*D3D11_SO_OUTPUT_COMPONENT_COUNT(128) not 5. Pls can you look in this code and give me the way or hope of implement it correctly?? Thanks a lot for help.
Structure of particle
struct Particle{
Particle() {}
Particle(float x, float y, float z,float vx, float vy, float vz,float
l /*UINT typ*/)
:InitPos(x, y, z), InitVel(vx, vy, vz), Age(l) /*, Type(typ)*/{}
XMFLOAT3 InitPos;
XMFLOAT3 InitVel;
float Age;
//UINT Type;
};
SO Entry
D3D11_SO_DECLARATION_ENTRY PartlayoutSO[] =
{
{ 0,"POSITION", 0, 0 , 3, 0 }, // output all components of position
{ 0,"VELOCITY", 0, 0, 3, 0 },
{ 0,"AGE", 0, 0, 1, 0 }
//{ 0,"TYPE", 0, 0, 1, 0 }
};
Global Variables
//streamout shaders
ID3D11VertexShader* Part_VSSO;
ID3D11GeometryShader* Part_GSSO;
ID3DBlob *Part_GSSO_Buffer;
ID3DBlob *Part_VSSO_Buffer;
//normal shaders
ID3D11VertexShader* Part_VS;
ID3D11GeometryShader* Part_GS;
ID3DBlob *Part_GS_Buffer;
ID3D11PixelShader* Part_PS;
ID3DBlob *Part_VS_Buffer;
ID3DBlob *Part_PS_Buffer;
ID3D11Buffer* PartVertBufferInit;
//ID3D11Buffer* Popy;
ID3D11Buffer* mDrawVB;
ID3D11Buffer* mStreamOutVB;
ID3D11InputLayout* PartVertLayout;// I try to set input layout too
void ParticleSystem::InitParticles()
{
mFirstRun = true;
srand(time(NULL));
hr = D3DCompileFromFile(L"ParticleVertexShaderSO4.hlsl", NULL,
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "vs_5_0", NULL, NULL,
&Part_VSSO_Buffer, NULL);
hr = D3DCompileFromFile(L"ParticleGeometryShaderSO4.hlsl", NULL,
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "gs_5_0", NULL, NULL,
&Part_GSSO_Buffer, NULL);
UINT StrideArray[1] = { sizeof(Particle) };//I try to set static 28 bits-7*4
per float
hr = device->CreateVertexShader(Part_VSSO_Buffer->GetBufferPointer(),
Part_VSSO_Buffer->GetBufferSize(), NULL, &Part_VSSO);
hr = device->CreateGeometryShaderWithStreamOutput(Part_GSSO_Buffer-
>GetBufferPointer(), Part_GSSO_Buffer->GetBufferSize(), PartlayoutSO ,3/*
sizeof(PartlayoutSO)*/ , StrideArray, 1,D3D11_SO_NO_RASTERIZED_STREAM,
NULL,&Part_GSSO);
//Draw Shaders
hr = D3DCompileFromFile(L"ParticleVertexShaderDRAW4.hlsl", NULL,
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "vs_5_0", NULL, NULL,
&Part_VS_Buffer, NULL);
hr = D3DCompileFromFile(L"ParticleGeometryShaderDRAW4.hlsl", NULL,
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "gs_5_0", NULL, NULL,
&Part_GS_Buffer, NULL);
hr = D3DCompileFromFile(L"ParticlePixelShaderDRAW4.hlsl", NULL,
D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", "ps_5_0", NULL, NULL,
&Part_PS_Buffer, NULL);
hr = device->CreateVertexShader(Part_VS_Buffer->GetBufferPointer(),
Part_VS_Buffer->GetBufferSize(), NULL, &Part_VS);
hr = device->CreateGeometryShader(Part_GS_Buffer->GetBufferPointer(),
Part_GS_Buffer->GetBufferSize(), NULL, &Part_GS);
hr = device->CreatePixelShader(Part_PS_Buffer->GetBufferPointer(),
Part_PS_Buffer->GetBufferSize(), NULL, &Part_PS);
BuildVertBuffer();
}
void ParticleSystem::BuildVertBuffer()
{
D3D11_BUFFER_DESC vertexBufferDesc1;
ZeroMemory(&vertexBufferDesc1, sizeof(vertexBufferDesc1));
vertexBufferDesc1.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc1.ByteWidth = sizeof(Particle)*1; //*numParticles;
vertexBufferDesc1.BindFlags = D3D11_BIND_VERTEX_BUFFER;// |
D3D11_BIND_STREAM_OUTPUT;
vertexBufferDesc1.CPUAccessFlags = 0;
vertexBufferDesc1.MiscFlags = 0;
vertexBufferDesc1.StructureByteStride = 0;// I tried to comment this too
Particle p;
ZeroMemory(&p, sizeof(Particle));
p.InitPos = XMFLOAT3(0.0f, 0.0f, 0.0f);
p.InitVel = XMFLOAT3(0.0f, 0.0f, 0.0f);
p.Age = 0.0f;
//p.Type = 100.0f;
D3D11_SUBRESOURCE_DATA vertexBufferData1;
ZeroMemory(&vertexBufferData1, sizeof(vertexBufferData1));
vertexBufferData1.pSysMem = &p;//było &p
vertexBufferData1.SysMemPitch = 0;
vertexBufferData1.SysMemSlicePitch = 0;
hr = device->CreateBuffer(&vertexBufferDesc1, &vertexBufferData1,
&PartVertBufferInit);
ZeroMemory(&vertexBufferDesc1, sizeof(vertexBufferDesc1));
vertexBufferDesc1.ByteWidth = sizeof(Particle) * numParticles;
vertexBufferDesc1.BindFlags = D3D11_BIND_VERTEX_BUFFER |
D3D11_BIND_STREAM_OUTPUT;
hr = device->CreateBuffer(&vertexBufferDesc1, 0, &mDrawVB);
hr = device->CreateBuffer(&vertexBufferDesc1, 0, &mStreamOutVB);
}
void ParticleSystem::LoadDataParticles()
{
UINT stride = sizeof(Particle);
UINT offset = 0;
//Create the Input Layout
//device->CreateInputLayout(Partlayout, numElementsPart, Part_VSSO_Buffer-
//>GetBufferPointer(),
// Part_VSSO_Buffer->GetBufferSize(), &PartVertLayout);
//Set the Input Layout
//context->IASetInputLayout(PartVertLayout);
//Set Primitive Topology
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
if (mFirstRun)
{
// context->CopyResource(Popy, PartVertBufferInit);
context->IASetVertexBuffers(0, 1, &PartVertBufferInit, &stride,
&offset);
}
else
{
context->IASetVertexBuffers(0, 1, &mDrawVB, &stride, &offset);
}
context->SOSetTargets(1, &mStreamOutVB, &offset);
context->VSSetShader(Part_VSSO, NULL, 0);
context->GSSetShader(Part_GSSO, NULL, 0);
context->PSSetShader(NULL, NULL, 0);
//context->PSSetShader(Part_PS, NULL, 0);
ID3D11DepthStencilState* depthState;//disable depth
D3D11_DEPTH_STENCIL_DESC depthStateDesc;
depthStateDesc.DepthEnable = false;
depthStateDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
device->CreateDepthStencilState(&depthStateDesc, &depthState);
context->OMSetDepthStencilState(depthState, 0);
if (mFirstRun)
{
//mFirstRun;
context->Draw(1, 0);
mFirstRun = false;
}
else
{
context->DrawAuto();
}
//}
// done streaming-out--unbind the vertex buffer
ID3D11Buffer* bufferArray[1] = { 0 };
context->SOSetTargets(1, bufferArray, &offset);
// ping-pong the vertex buffers
std::swap(mStreamOutVB, mDrawVB);
// Draw the updated particle system we just streamed-out.
//Create the Input Layout
//device->CreateInputLayout(Partlayout, numElementsPart, Part_VS_Buffer-
//>GetBufferPointer(),
// Part_VS_Buffer->GetBufferSize(), &PartVertLayout);
//Set the normal Input Layout
//context->IASetInputLayout(PartVertLayout);
context->IASetVertexBuffers(0, 1, &mDrawVB, &stride, &offset);
ZeroMemory(&depthStateDesc, sizeof(depthStateDesc));
depthStateDesc.DepthEnable = true;
depthStateDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
device->CreateDepthStencilState(&depthStateDesc, &depthState);
context->OMSetDepthStencilState(depthState, 0);
//I tried add normal layout here the same like Entry SO but no changes
//Set Primitive Topology
//context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
context->VSSetShader(Part_VS, NULL, 0);
context->GSSetShader(Part_GS, NULL, 0);
context->PSSetShader(Part_PS, NULL, 0);
context->DrawAuto();
//mFirstRun = true;
context->GSSetShader(NULL, NULL, 0);
}
void ParticleSystem::RenderParticles()
{
//mFirstRun = true;
LoadDataParticles();
}
And the code of shaders:
VertexShader to stream out
struct Particle
{
float3 InitPos : POSITION;
float3 InitVel : VELOCITY;
float Age : AGE;
//uint Type : TYPE;
};
Particle main(Particle vin)
{
return vin;// just push data into geomtrywithso
}
GeometrywithSo
struct Particle
{
float3 InitPos : POSITION;
float3 InitVel : VELOCITY;
float Age : AGE;
//uint Type : TYPE;
};
float RandomPosition(float offset)
{
float u = Time + offset;// (Time + offset);
float v = ObjTexture13.SampleLevel(ObjSamplerState, u, 0).r;
return (v);
}
[maxvertexcount(6)]
void main(
point Particle gin[1],
inout PointStream< Particle > Output
)
{
//gin[0].Age = Time;
if ( StartPart == 1.0f )
{
//if (gin[0].Age < 100.0f)
//{
for (int i = 0; i < 6; i++)
{
float3 VelRandom; //= 5.0f * RandomPosition((float)i / 5.0f);
VelRandom.y = 10.0f+i;
VelRandom.x = 35 * i* RandomPosition((float)i / 5.0f);//+ offse;
VelRandom.z = 10.0f;//35*i * RandomPosition((float)i / 5.0f);
Particle p;
p.InitPos = VelRandom;//float3(0.0f, 5.0f, 0.0f); //+ VelRandom;
p.InitVel = float3(10.0f, 10.0f, 10.0f);
p.Age = 0.0f;//VelRandom.y;
//p.Type = PT_FLARE;
Output.Append(p);
}
Output.Append(gin[0]);
}
else if (StartPart == 0.0f)
{
if (gin[0].Age >= 0)
{
Output.Append(gin[0]);
}
}
}
If I change Age in geometry with so: for example Age += Time from const buffer
In geometry shader its fine once but in draw shader it is 0 and next time if it is reading in geometry with so it is 0 too.
Vertex shader to draw
struct VertexOut
{
float3 Pos : POSITION;
float4 Colour : COLOR;
//uint Type : TYPE;
};
struct Particle
{
float3 InitPos : POSITION;
float3 InitVel : VELOCITY;
float Age : AGE;
// uint Type : TYPE;
};
VertexOut main(Particle vin)
{
VertexOut vout;
float3 gAccelW = float3(0.0f, -0.98f, 0.0f);
float t = vin.Age;
//float b = Time/10000;
// constant Acceleration equation
vout.Pos = vin.InitVel+ (0.7f * gAccelW)*Time/100;
//vout.Pos.x = t;
vout.Colour = float4(1.0f, 0.0f, 0.0f, 1.0f);
//vout.Age = vout.Pos.y;
//vout.Type = vin.Type;
return vout;
}
Geometry shader to change point into line
struct VertexOut
{
float3 Pos : POSITION;
float4 Colour : COLOR;
//uint Type : TYPE;
};
struct GSOutput
{
float4 Pos : SV_POSITION;
float4 Colour : COLOR;
//float2 Tex : TEXCOORD;
};
[maxvertexcount(2)]
void main(
point VertexOut gin[1],
inout LineStream< GSOutput > Output
)
{
float3 gAccelW = float3(0.0f, -0.98f, 0.0f);
//if (gin[0].Type != PT_EMITTER)
{
float4 v[2];
v[0] = float4(gin[0].Pos, 1.0f);
v[1] = float4((gin[0].Pos + gAccelW), 1.0f);
GSOutput gout;
[unroll]
for (int i = 0; i < 2; ++i)
{
gout.Pos = mul(v[i], WVP);// mul(v[i], gViewProj);
gout.Colour = gin[0].Colour;
Output.Append(gout);
}
}
}
And pixel Shader
struct GSOutput
{
float4 Pos : SV_POSITION;
float4 Colour : COLOR;
};
float4 main(GSOutput pin) : SV_TARGET
{
return pin.Colour;
}

Error with VAO on Nexus 4 device only

I've got a strange error on my nexus 4 with OpenGL ES2 when I use vertex array objects.
Here is some informations:
Everything work when I don't use VAO
Everything work on others device and on an Ipad 2 with and without VAO
glGetError() didn't return error
Due to the error some glitch appear in the game (some elements take another apparence)
My VBO are dynamics (I update them with glBufferData)
Here is the error:
Adreno-ES20(16818): : validate_vertex_attrib_state: No vertex attrib is enabled in a draw call!
And here is my code:
void Renderer::setVertexBuffer( Uint32 stream, const Base* vertexBuffer, std::size_t stride, Uint32 startVertex, Uint32 endVertex )
{
static const bool VAOSupported = this->isExtensionPresent(VertexArrayObject);
if( VAOSupported )
{
if( vertexBuffer->vao.isReady() == false )
{
// Bind VAO.
glBindVertexArrayOES( vertexBuffer->vao.getId() );
// Bind filled VBO.
glCheck( glBindBuffer( GL_ARRAY_BUFFER, vertexBuffer->getId() ) );
// Set attributs with vertex format.
this->applyVertexFormat( startVertex, endVertex );
// Unbind buffer and VAO.
glBindVertexArrayOES(0);
vertexBuffer->vao.isReady(true);
}
glBindVertexArrayOES( vertexBuffer->vao.getId() );
}
else
{
glBindVertexArrayOES(0);
glCheck( glBindBuffer( GL_ARRAY_BUFFER, vertexBuffer->getId() ) );
this->applyVertexFormat( startVertex, endVertex );
}
}
////////////////////////////////////////////////////////////
void Renderer::setIndexBuffer( const Buffer* indexBuffer, std::size_t stride )
{
glCheck( glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, indexBuffer->getId() ) );
this->usedIndexBufferStride = stride;
}
////////////////////////////////////////////////////////////
void Renderer::applyVertexFormat( Uint32 startVertex, Uint32 endVertex )
{
const Uint32 stride = this->vertexFormat->getStride();
for( Uint32 i = 0; i < this->vertexFormat->getAttributCount(); i++ )
{
const VertexElement& element = this->vertexFormat->getAttribut(i);
glCheck( glEnableVertexAttribArray( element.usage ) );
glCheck( glVertexAttribPointer( element.usage,
element.type,
element.type,
element.normalize,
stride,
BUFFER_OFFSET(element.offset + startVertex * stride ) ) );
}
}
And here is how I use it :
renderer->setFormat(geometry->getFormat()); // Only save a pointer to the format to use in apply method.
renderer->setVertexBuffer(geometry->getVertexBuffer());
renderer->setIndexBuffer(geometry->getIndexBuffer());
renderer->draw(GL_TRIANGLES, geometry->indiceCount);
Are you sure usage is an appropriate name for the field that defines which attribute array to associate the pointer with? Buffer objects already have a property called usage (e.g. GL_DYNAMIC_DRAW). location might make more sense.
You have a much more serious issue in your code, however:
element.type cannot be both the type of your data and the number of components. glVertexAttribPointer (...) only accepts 1, 2, 3 or 4 components, an enumerant like GL_FLOAT has a value much larger than 4.
Assuming glCheck( ... ) correctly wraps glGetError (...), this situation should be indicating GL_INVALID_VALUE.
This leads me to believe that your loop in void Renderer::applyVertexFormat( Uint32 startVertex, Uint32 endVertex ) is never triggered.

Resources